-1

I’m learning C using Xcode 8 and the compiler doesn’t run any code after a while- or for-loop executes. is this a bug? how can I fix it?

In the example provided below printf("code executed after while-loop"); never executes

#include <stdio.h>

int getTheLine(char string[]);

int getTheLine(char string[]) {

  char character;
  int index;
  index = 0;

  while ((character = getchar()) >= EOF) {

    string[index] = character;
    ++index;
  }

  printf("code executed after while-loop");
  return index;
}

int main(int argc, const char * argv[]) {

  char string[100];
  int length = getTheLine(string);
  printf("length %d\n", length);

  return 0;
}
Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
  • You could start showing us your code. – Jabberwocky Jun 14 '17 at 08:23
  • 2
    The compiler should not *run* any code at all. It should compile [*translation units*](https://en.wikipedia.org/wiki/Translation_unit_(programming)) into object files which are then linked into an executable. The IDE can then start a process to run the executable. – Some programmer dude Jun 14 '17 at 08:23
  • 1
    More to the point, please [read about how to ask good questions](http://stackoverflow.com/help/how-to-ask) and learn how to create a [Minimal, Complete, and Verifiable Example](http://stackoverflow.com/help/mcve). – Some programmer dude Jun 14 '17 at 08:24
  • 1
    Please edit your question to include code, don't post it as comments. And please make it *complete*, especially with variable declarations (in this case I think that's very important). – Some programmer dude Jun 14 '17 at 08:25
  • 6
    Please note that `getchar()` returns `int`, since `EOF` does not fit in a `char`. – unwind Jun 14 '17 at 08:32
  • one should file a bug "xcode/clang does not support for-loop" - no, joke :-) you probably have an infinite or at least very long running loop. Show your code, please. – Stephan Lechner Jun 14 '17 at 08:32
  • @CristianLăpușan Please don't edit important aspects of the posted code **after** answers have been posted - especially when the answers quotes that specific part of the code. By doing that the answers are invalidated. – Support Ukraine Jun 14 '17 at 10:07

3 Answers3

2

getchar returns an int not a char, and comparison with EOF should be done with the != operator instead of the >= operator.

...
int character;   // int instead of char
int index;
index = 0;

while ((character = getchar()) != EOF) {  // != instead of >=
...
Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
2

It's the >= EOF, which will let the condition be always true. The reason is that a "valid" result of getchar() will be a positive integer, and a "non-valid" result like end-of-file will be EOF, which is negative (cf. getchar()):

EOF ... integer constant expression of type int and negative value

Hence, any valid result from getchar will be >EOF, while the end-of-file-result will be ==EOF, such that >= EOF will always match.

Write != EOF instead.

Note further that you do not terminate your string by the string-terminating-character '\0', such that using string like a string (e.g. in a printf("%s",string)) will yield undefined behaviour (crash or something else probably unwanted). So write at least:

while ((character = getchar()) != EOF) {
    string[index] = character;
    ++index;
}
string[index]='\0';

Then there is still the issue that you may write out of bounds, e.g. if one enters more then 100 characters in your example. But checking this is now beyond the actual question, which was about the infinite loop.

Stephan Lechner
  • 34,891
  • 4
  • 35
  • 58
  • If I exit the function early, say I insert immediately after the loop "if (character == 47) {return index;}", then the code runs fine – Cristian Lăpușan Jun 14 '17 at 08:45
  • @Cristian Lăpușan: I suppose you mean "inside the loop", because your loop will never end; so "code executed after while-loop" is never printed, right? – Stephan Lechner Jun 14 '17 at 08:50
2

The symbolic constant EOF is an integer constant, of type int. It's (usually) defined as a macro as -1.

The problem is that the value -1 as an (32-bit) int has the value 0xffffffff and as a (8-bit) char the same value would be 0xff. Those two values are not equal. Which in turn means that your loop condition will never be false, leading to an infinite loop.

The solution to this problem is that all standard functions that reads characters returns them as an int. Which means your variable character needs to be of that type too.

Important note: It's a compiler implementation detail if plain char is a signed or an unsigned type. If it is signed then a comparison to an int would lead to sign extension when the char value is promoted in the comparison. That means a signed char with the value 0xff would be extended to the int value 0xffffffff. That means if char is signed then the comparison would work.

This means that your compile have char as unsigned char. So the unsigned char value 0xff after promotion to int will be 0x000000ff.


As for why the value -1 becomes 0xffffffff is because of how negative numbers are usually represented on computers, with something called two's complement.


You also have another couple of flaws in your code.

The first is that since the loop is infinite you will go way out of bounds of the string array, leading to undefined behavior (and a possible crash sooner or later). The solution to this is to add a condition to make sure that index never reaches 100 (in the specific case of your array, should really be passed as an argument).

The second problem is that if you intend to use the string array as an actual string, you need to terminate it. Strings in C are actually called null terminated strings. That terminator is the character '\0' (equal to integer 0), and need to be put at the end of every string you want to pass to a standard function handling such strings. Having this terminator means that an array of 100 characters only can have 99 characters in it, to be able to fit the terminator. This have implications to the solution to the above problem. As for how to add the terminator, simply do string[index] = '\0'; after the loop (if index is within bounds of course).

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • it does not work.. – Cristian Lăpușan Jun 14 '17 at 08:48
  • 1
    @CristianLăpușan How does *what* "not work"? Did you change the type of `character` to `int`? Are you doing something else you do not show us? Have you tried stepping through the code in a debugger? And have you tried adding a (trailing) newline to the string you print after the loop (since output to `stdout` is by default line-buffered)? – Some programmer dude Jun 14 '17 at 08:51
  • Upvoted for all the details you bring in. But just for me to understand: doesn't integral promotion in `(char)-1 == (int)-1` make sure that `(char)-1` is actually extended to `0xffffffff`? – Stephan Lechner Jun 14 '17 at 08:58
  • @StephanLechner That depends. I should probably add that `char` can be either `signed` *or* `unsigned` (it's up to the compiler) and if it's `signed` then yes there would be sign-extension. Not so when `char` is `unsigned` (which seems to be the case here, or it should work). – Some programmer dude Jun 14 '17 at 09:03
  • I appreciate your input. thank you very much! the problem is that even code out of learn book does not get executed if a while-loop precedes – Cristian Lăpușan Jun 14 '17 at 09:06
  • @CristianLăpușan please tell us which keys _exactly_ you press once the program is running, so we can understand why it doesn't work on your computer. – Jabberwocky Jun 14 '17 at 09:22
  • @CristianLăpușan If you still can't make it work after changing the type and added the newline when printing, then please post a new question (with the *updated* code) about it. – Some programmer dude Jun 14 '17 at 09:26
  • found the solution. command + D + D (command followed by double pressing D) to signal EndOfFile. very easy! the while-loop exited and code after the loop got executed as well. I kept character variable of type char. it didn’t matter if I chose int or char. thank you for all of your input! – Cristian Lăpușan Jun 14 '17 at 20:30