1

I'm new in C and I'm dealing with an issue when trying to input a string. More specifically, when printing the string the character 'Ν' appears in the end of it and as a result, I cannot measure the exact numbers of characters. Here is my code:

int main()
{
    int j = 0;
    char c[15];
    printf("Give surname: ");
    scanf(" %s", c);
    for (int i = 0; i<sizeof(c) / sizeof(c[1]); i++)
    {
        if (isalpha(c[i]))
        {
            printf("%c ", c[i]);
            j++;
        }
    }
    printf("\nNumber of characters: %d", j);

    return 0;
}

For example: If the input is "john" then I get the following output:

enter image description here

What am I doing wrong?

WhozCraig
  • 65,258
  • 11
  • 75
  • 141
popist
  • 83
  • 8
  • 2
    Your loop is iterating far more characters than read from `stdin`. – WhozCraig Sep 01 '18 at 20:07
  • 3
    A likely reason is that `scanf` added a 0-byte at the end of the string when you typed in your reply, but you're not checking for that, instead you're outputting 15 characters no matter what. You should learn about string functions in C, like `strlen` and instead of outputting the characters manually, perhaps just ask `printf` to do it for you? – Lasse V. Karlsen Sep 01 '18 at 20:07
  • 1
    You didn't initialize `c`, so it contains indeterminate data after the part that is set by `scanf()`. It you sent the output through a program that prints each character visibly (e.g. `od` or `xxd -g 1`) you'd see a whole lot of other characters in the output — one null byte, and some other non-printing (control) characters, and more spaces than you thought, too. – Jonathan Leffler Sep 01 '18 at 20:22
  • the posted code does not compile!. It seems to be missing the include statements for the needed header files. Are you expecting us to guess as to which header files your actual code includes? – user3629249 Sep 02 '18 at 01:07
  • the operator `sizeof` returns a `size_t`, (which is usually an unsigned long int) however, the posted code is comparing that value to a `int` – user3629249 Sep 02 '18 at 01:09
  • regarding: `scanf(" %s", c);` 1) always check the returned value to assure the operation was successful. the function: `scanf()` returns the number of successful input/conversions, in this case, 1. 2) when using the input format specifiers '%s' and/or '%[...]' always include a MAX CHARACTERS modifier that is one less than the length of the input buffer. That avoids any possibility of a buffer overflow and the resulting undefined behavior – user3629249 Sep 02 '18 at 01:14
  • regarding: `i – user3629249 Sep 02 '18 at 01:17
  • the variable 'j' is completely unneeded as the count of characters is already contained in the variable 'i', especially after correcting the second expression in the 'for()` statement – user3629249 Sep 02 '18 at 01:20
  • the string input by `scanf()` will have appended a NUL byte to the input buffer, so suggest the `for()` statement be modified to: `for ( int i = 0; c[i]; i++)` – user3629249 Sep 02 '18 at 01:23

3 Answers3

3

That is because you are using sizeof operator on array of chars which is longer than the actual string. You can use strlen from string.h as stated above, or simply iterate over chars till the \0, just like that:

char * p = c;
while(*p++)
    if (isalpha(*p))
        printf("%c ", *p);

And if you are interested in number of chars you can just substract the pointers.

arorias
  • 318
  • 3
  • 14
3

Your loop limit is wrong. It is causing you to evaluate indeterminate data. Things specifically wrong:

  • Not checking for success of scanf
  • Not specifying a length-limited format string to avoid overflowing the c[] array.
  • As mentioned, iterating the entire array rather than just the data you assume was read successfully.

All of these can be fixed, some of them trivially.

  • Check that scanf returned 1
  • As your c array is 15 characters, and space must be accounted for the terminating nullchar, use %14s for your format string
  • Either use strlen as the limit of your for (in some fashion, be it saved to a temporary or directly in the conditional clause) or use a pointer.

Regarding the last item, I prefer the latter, as you're only scanning the string once. strlen will scan the string to find the terminator, thereby calculating the length and returning it. Scanning it again during iteration then ensues. You can eliminate the strlen scan by simply not using it, rather using a pointer instead, and stopping scanning when the terminator is discovered.

Rewritten, this is the result:

#include <stdio.h>
#include <ctype.h>

int main()
{
    char c[15];
    int j = 0;

    printf("Give surname: ");
    if (scanf("%14s", c) == 1)
    {
        for (const char *p = c; *p; ++p)
        {
            if (isalpha(*p))
            {
                printf("%c ", *p);
                ++j;
            }
        }

        printf("\nNumber of characters: %d", j);
    }

    return 0;
}

Input

123john456

Output

j o h n
Number of characters: 4
WhozCraig
  • 65,258
  • 11
  • 75
  • 141
2

Try using the strlen() function instead. It checks for the null-termination character at the end of your actual string (as opposed to the full array, which may contain garbage characters after the null-termination character).

int length = strlen(c);
for (int i = 0; i < length; i++){

Remember to #include <string.h>

See it in action here: https://repl.it/repls/SugaryUnfoldedCleaninstall

If you're wondering why you need to rely on a function to do this, have a look at the source of strlen(). Writing a function like this that performs well and is correct in all cases is harder than it looks.

Further Reading
How to iterate over a string in C

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
  • It's better not to use `strlen(c)` in the condition — it might be optimized so that it is called but once, but it might not. (The general problem diagnosis is correct, though.) – Jonathan Leffler Sep 01 '18 at 20:20