6

I'm writing a function that replaces blank spaces into '-' (<- this character). I ultimately want to return how many changes I made.

#include <stdio.h>
int replace(char c[])
{
    int i, cnt;
    cnt = 0;
    for (i = 0; c[i] != EOF; i++)
        if (c[i]==' ' || c[i] == '\t' || c[i] == '\n')
        {
            c[i] = '-';
            ++cnt;
        }
    return cnt;
}

main()
{
    char cat[] = "The cat sat";
    int n = replace(cat);
    printf("%d\n", n);
}

The problem is, it correctly changes the string into "The-cat-sat" but for n, it returns the value 3, when it's supposed to return 2. What have I done wrong?

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
SoSueat
  • 63
  • 5
  • 1
    `c[i] != EOF`-->> `c[i] != 0` – wildplasser Oct 14 '17 at 15:35
  • to add to what @wildplasser said, `c[i] == '\n'`..you really need that? – Sourav Ghosh Oct 14 '17 at 15:35
  • its giving the correct output for me – krpra Oct 14 '17 at 15:43
  • @krpra - still it's wrong. Comparing to EOF is not what you want – Support Ukraine Oct 14 '17 at 15:44
  • @4386427 yeah i noticed that but output is correct – krpra Oct 14 '17 at 15:45
  • 4
    @krpra That's the whole thing about Undefined Behavior. At its worst, it seems to work – Support Ukraine Oct 14 '17 at 15:46
  • It outputs 3 for me when I compile with gcc and 2 when I compile with cc. – klutt Oct 14 '17 at 15:46
  • @4386427 yeah you are right. – krpra Oct 14 '17 at 15:47
  • 1
    Everyone says to not use EOF, but no one seems to say why. You would use EOF only when reading from a file (EOF -> End Of File). When working with char array (pointer), it will always be terminated by a `'\0'` character, thus, you would use it to break out of the loop. – Nik Oct 14 '17 at 15:51
  • @Nik - you could post an answer where you explain that in details :-) – Support Ukraine Oct 14 '17 at 15:52
  • @klutt - Different output from different compilers... nice example of UB – Support Ukraine Oct 14 '17 at 15:54
  • @Nik because EOF != `\0` (e.g. in CPM EOF = 0x1c) in stdio.h on linux EOF == -1 .. so that's why. `\0` is the C guarantee of EOS (irrespective of the actual memory value of it on a hardware) – Ahmed Masud Oct 14 '17 at 17:26
  • @AhmedMasud, good suggestion...sometimes we take this knowledge for granted. I augmented my answer to provide more info on the EOF macro. – Nik Oct 14 '17 at 17:48
  • @SouravGhosh yeah just incase the user presses enter – SoSueat Oct 15 '17 at 16:05
  • @Nik so sth like ((c = getchar()) != EOF) is completely different from just string right?? – SoSueat Oct 15 '17 at 16:07
  • A string, or `char*` is a contiguous block of memory that is made up of `char` and always ends on a `\0` character. A text file is not governed by the C standard, and may possibly contain `\0` characters (although very unlikely). In addition, text files do not have any terminators. When you read a text file, the system will append EOF as the last character in the stream. Does that answer your question? – Nik Oct 15 '17 at 16:57

4 Answers4

1

@4386427 suggested this should be another answer. @wildplasser already provided the solution, this answer explains EOF and '\0'.

You would use EOF only when reading from a file (EOF -> End Of File). See this discussion. EOF is used to denote the end of file, and its value is system dependent. In fact, EOF is rather a condition than a value. You can find great explainations in this thread. When working with char array or a char pointer, it will always be terminated by a '\0' character, and there is always exactly one of those, thus, you would use it to break out of the loop when iterating through an array/pointer. This is a sure way to ensure that you don't access memory that is not allocated.

Nik
  • 1,780
  • 1
  • 14
  • 23
0
  • A string ends with a 0 (zero) value, not an EOF (so: the program in the question will scan the string beyond the terminal\0 until it happens to find a -1 somewhere beyond; but you are already in UB land, here)
  • [sylistic] the function argument could be a character pointer (an array argument cannot exist in C)
  • [stylistic] a pointer version wont need the 'i' variable.
  • [stylistic] The count can never be negative: intuitively an unsigned counter is preferred. (it could even be a size_t, just like the other string functions)
  • [stylistic] a switch(){} can avoid the (IMO) ugly || list, it is also easier to add cases.

unsigned replace(char *cp){
    unsigned cnt;
    for(cnt = 0; *cp ; cp++) {
        switch (*cp){
        case ' ' : case '\t': case '\n':
                *cp = '-';
                cnt++; 
        default:
                break;
                }
        }
return cnt;
}
wildplasser
  • 43,142
  • 8
  • 66
  • 109
0

EOF used in the for loop end condition is the problem as you are not using is to check end of file/stream.

for (i = 0; c[i] != EOF; i++)

EOF itself is not a character, but a signal that there are no more characters available in the stream.

If you are trying to check end of line please use

for (i = 0; c[i] != "\0"; i++)
MarianD
  • 13,096
  • 12
  • 42
  • 54
0
#include <stdio.h>

int repl(int c);

int main(void){
    int c, nc;
    nc =0;

    while ((c=getchar())!=EOF)
        nc = replc(c);

    printf("replaced: %d times\n", nc);

    return 0;
}

int replc(int c){
    int nc = 0;
    for(; (c = getchar())!=EOF; ++c)
       if (c == ' '){
          putchar('-');
          ++nc;
       } else putchar(c);
    return nc;
}