0

My goal in the code is to initialize string with 80 chars, and only when the user typing char that is not '\0' ,' ' ,'\t' ,'\n' . to print "illegal command".

Now if the user typing for example 3 chars of space and press enter . the output is (80-4)=76 times "illegal command". and it does not need to print it at all because all the chars that the user typed was one of '\0', ' ', '\t', '\n'.

Please help me in that case.

The code :

void main() {
  int i;
  char str[80]="";
  gets_s(str, sizeof(str));
  for (i = 0; i < 80; i++)
  {
    if ((str[i] != '\n' && str[i] != '\0' && str[i] != '\t' && str[i] != ' '))
    {
      printf_s("illegal character: %c\n", str[i]);
    }
  }
}

Output

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
Or Simhon
  • 53
  • 3
  • 1
    Maybe put a `break` statement after the `printf_s`. – Jabberwocky May 01 '18 at 09:22
  • that not my intention friend . at last i will do this, but that not the problem. the problem is that the compiler entered to the condition Although i type only spaces and press enter. if i will type 80 times space it will not enter to the condition. but if i press 1 time space and then enter, the output will be (80-2) times "illegal command" – Or Simhon May 01 '18 at 09:25
  • Please [edit] your question, you need to provide some examples of input and desired output. – Jabberwocky May 01 '18 at 09:28
  • 1
    Also, you might want to specify your system (OS, compiler, etc), since the problem might be system-dependent. – anatolyg May 01 '18 at 09:30
  • `void main()` --> `int main(void)`. What is your output if you initialize `str` as `char str[80] = {'\0'};` ? – Bob__ May 01 '18 at 09:34
  • Neither of @Bob__ 's comments have anything to do with the actual problem. – Steve Summit May 01 '18 at 10:31
  • I suggest changing your error message to `printf("illegal character: %c\n", str[i])`, so that you can see each illegal character as it's detected. If you're having issues with nonprintable characters, you could make it `printf("illegal character: %c (0x%02x)\n", str[i], str[i])`. – Steve Summit May 01 '18 at 10:39
  • @SteveSummit hey friend , yes you indeed understood what i am said, for me it is just work different. if I hit Enter, it prints 79 time "illegal command" or Space Enter it prints 78 time "illegal command" .. what you think can be the problem ? – Or Simhon May 01 '18 at 10:50
  • @OrSimhon See my answer below. – Steve Summit May 01 '18 at 10:53
  • Temporarily delete `gets_s(str, sizeof(str));` and report the output to discern the initialization state of `str[]`. – chux - Reinstate Monica May 01 '18 at 12:04
  • @OrSimhon Those little boxes in the image you posted are what I was referring to as "nonprintable characters". Instead of `%c`, use `%02x`. – Steve Summit May 01 '18 at 15:12
  • To really understand what's going on here, what we should do is add the loop `for(i = 0; i < 80; i++) printf("%02x ", str[i]); printf("\n");` to see exactly what's in the array. And we need to do this twice: once before the call to `gets_s`, and then again after the call to `gets_s`. We have to see exactly how the array is getting initialized, and we have to see exactly how `gets_s` is changing it. Then all should become clear. – Steve Summit May 01 '18 at 15:15

2 Answers2

2

My goal in the code is to initialize string with 80 chars, and only when the user typing char that is not \0 , ,\t ,\n . to print "illegal com

It appears that if the user only enters '\0', ' ', '\t', '\n', no message is printed.

char str[80]=""; is specified to initialize the entire array, yet may not be OP's problem.

Yet it is the footnote1 and comment that may explain OP's unexpected output.


What makes this challenging is that user input may contain null characters, and not just the appended one.

Using getchar() would be a direct approach.

int ch;
while ((ch = getchar()) != '\n' && ch != EOF) {
  if (ch != ' ' && ch != '\t' && ch != '\0') {
    printf_s("illegal character code: %d\n", ch);
  }
}

gets_s(); is trickier to use for the task as it does not return the length read and input may consists of embedded null characters.

To detect embedded null characters, the buffer will not end with a '\n' and it is hoped (though not specified.1) that the unused portion remain unchanged. So by pre-filling with '\n' code can distinguish between the appended null characters and one that is read.

int main(void) {
  int i;
  char str[80];
  memset(str, '\n', sizeof str);

  if (gets_s(str, sizeof str)) {
    int length = sizeof str;
    while (length > 0) {
      length--;
      if (str[length] == '\0') break;  // found appended null character
    }
    for (int i=0; i<length; i++) {
      if (str[i] != '\0' && str[i] != '\t' && str[i] != ' ') {
        printf("illegal character code: %d\n", str[i]);
      }
    }  
  }
}        

I prefer the getchar() approach.


1 The value of the buffer after the appended null character is not specified to be unchanged - yet that is the common case. Hmmmm, but if it was changed, that would explain OP's problem. So another reason to avoid gets_s(); here.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Interesting. So `gets_s` *could* change the values in the array after the appended null (as it does apparently, in the output you show in the question)? – Bob__ May 01 '18 at 11:58
  • @Bob__ That _may_ be the case and might be a "safety" feature of `gets_s()` to punish code the uses that data. A `gets_s()` like function that returned the length read would be more useful to cope with embedded _null characters_. – chux - Reinstate Monica May 01 '18 at 12:02
  • 1
    Just to make it explicit - the MS version of `gets_s` fills the rest of the buffer with bytes `0xfe`, some sort of "invalid marker bytes". This only happens in Debug mode. – anatolyg May 03 '18 at 16:33
1

When you said

char str[80] = "";

it looks like you did not actually initialize all 80 characters. You explicitly initialized the first character to '\0', but it looks like your compiler left the other 79 with random values. (More on this point later.)

When you said

for (i = 0; i < 80; i++)

you are asking to loop over all 80 characters in the array -- but this does not make sense. The gets_s function filled in only some characters -- as many characters as the user typed, plus one trailing '\0'. If the user typed fewer than 79 characters, many of the characters in str are still untouched (and perhaps still random).

Try changing the loop to

for (i = 0; str[i] != '\0'; i++)

or if you want to be on the safe side

for (i = 0; i < 80 && str[i] != '\0'; i++)

Because your program uses uninitialized memory, its behavior might be different on different systems. When I ran your program on my computer, evidently all 79 were also 0, meaning that I saw no extra error messages. (So at first I couldn't understand what you were talking about.) But it sounds like, on your system, they actually had random, nonzero values. You can see this if you change your error message to

printf("illegal character: 0x%02x\n", str[i]);

This will print the (hexadecimal) representations of all the "illegal" characters you saw. My guess is they'll be more or less random numbers.

(As chux points out in a comment, your compiler should have initialized those other 79 characters to 0, also, so it sounds like your compiler might be an older one, and buggy in this regard.)

Two other things you could try would be:

  1. Move the declaration of str[] outside of main(). If you do that, all of it will be initialized to 0, and your program will behave more as you expected it to.

  2. Change the declaration of str to char str[80] = " ";, where there are exactly 79 spaces between the "".

But neither of those changes is a particularly good idea. If the user types 6 characters, you really want to check only the 6 characters he explicitly typed, not all 80 of the characters that you initially allocated.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • 1
    "You initialized the first character to '\0', and the other 79 will end up with random values." --> No partial initializations in C. Those other 79 initialize likes a global `char`, to 0. – chux - Reinstate Monica May 01 '18 at 11:04
  • @chux Hmm, you're right. (I always forget that, I'm still getting used to this newfangled automatic array allocation.) Perhaps his compiler got this wrong; I can't think of any other explanation for the behavior he saw. – Steve Summit May 01 '18 at 11:26
  • 1
    @SteveSummit See [footnote](https://stackoverflow.com/a/50115553/2410359) to explain why `str[]` after the first 4 may have changed. – chux - Reinstate Monica May 01 '18 at 11:41