-2

I have declared an array b[3] and although I don't use it anywhere in the program, the program does not work correctly without it. It only prints out whatever bites the user's previous creation or whatever gets bitten by the user's previous creation. I don't know why this happens or how to make the program run correctly without b[3]. Here is my code:

#include <stdio.h>
#include <string.h>

main() {
    char a[100]="man";
    char b[3];

    printf ("A man is bitten by a spider and becomes spiderman.\n"
            "So in this motive start making stuff.\nTo end the program "
            "just click X on top right of the window\n\n");
    printf ("When you create sth really big, you go back to only having "
            "a man.\n\n");
    unsigned char f=1,x=3,i;

    while(1){
        printf ("You have a %s\n",a);
        /*presentation of the menu*/
        printf ("Press:\n"
                "\t1 for what you have to bite a spider.\n"
                "\t2 for what you have to bite a man.\n"
                "\t3 for what you have to bite spiderman.\n"
                "\t4 for what you have to get bitten by a spider.\n"
                "\t5 for what you have to get bitten by a man.\n"
                "\t6 for what you have to get bitten by spiderman.\n"
                "\t0 to go from the start\n");
        scanf("%hhu",&f);
        switch(f){
        case 0:
            strcpy(a,"man");
            x=2;
            break;
        case 1:
            x+=6;
            if(x<=100){
            strcat(a,"spider");
            }
            break;
            case 2:
            x+=3;
            if(x<=100){
            strcat(a,"man");
            }
            break;
            case 3:
            x+=9;
            if(x<=100){
            strcat(a,"spiderman"); 
            }
            break;
            case 4:
            x+=7;
            if(x<=100){
                for(i=x;i>=6;i--){
                    a[i]=a[i-6];
                }
                a[0]='s';
                a[1]='p';
                a[2]='i';
                a[3]='d';
                a[4]='e';
                a[5]='r';
            }
            break;
            case 5:
            x+=4;
            if(x<=100){
                for(i=x;i>=3;i--){
                    a[i]=a[i-3];
                }
                a[0]='m';
                a[1]='a';
                a[2]='n';
            }
            break;
            case 6:
            x+=10;
            if(x<=100){
                for(i=x;i>=9;i--){
                    a[i]=a[i-9];
                }
                a[0]='s';
                a[1]='p';
                a[2]='i';
                a[3]='d';
                a[4]='e';
                a[5]='r';
                a[6]='m';
                a[7]='a';
                a[8]='n';
            }
            break;
        }
        if(x>100){
            strcpy(a,"man");
            x=2;
        }
    }
}

Input:

1  

Output (with b[3]):

You have a manspider  

Output (without b[3]):

You have a spider  
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • 3
    Time to learn [how to debug small programs](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/). You probably have some undefined behavior popping up in yours. Most likely writing out of bound into some memory. `b` just takes the hit when it's present. – StoryTeller - Unslander Monica Jan 06 '18 at 21:45
  • I can't reproduce, you are probably invoking undefined behaviour somewhere – mdatsev Jan 06 '18 at 21:46
  • Can reproduce with MinGW, but as @mdatsev mentioned you probably have UB somewhere. – Holt Jan 06 '18 at 21:49
  • 1
    Switching `f` to `int` and `%hhu` to `%d` seems to solve the problem. – Holt Jan 06 '18 at 21:50
  • 1
    @Holt: Why would that solve the problem? Does it eliminate some error in the program, or does it merely work around the issue in that when you compile with MinGW, the program appears to work? – Eric Postpischil Jan 06 '18 at 21:52
  • Switching f to int takes 4 instead of 1 bytes so 3 extra. Just like b[3]. And the problem is that with b[2] the program still has the same problem as without b. Still thanks. It works with int. – michalis vazaios Jan 06 '18 at 21:56
  • Can you please give a "real" output, i.e. a complete one? I cannot imagine how your program can ever output `You have a manspider` without printing the `You have a ` a second time. Also the `Press:\n\t1 for what you...` is missing, isn't it? – Stephan Lechner Jan 06 '18 at 21:59
  • What is `x` supposed to be? It looks like some information about the end of the string in `a`. You initialize `x` to 3 and initialize `a` to “man”. But, when you reset `a` to “man” with `strcpy`, you set `x` to 2. And, in cases 4 and 5, where you insert “spider” (6 characters) or “man” (3) into `a`, you add 7 or 4 to `x`, rather than 6 or 3. I expect these discrepancies could cause problematic behavior later in your program. I do not see how they could cause a problem on the first input of 1. – Eric Postpischil Jan 06 '18 at 22:00
  • @Stephan Lechner:The program prints the "You have a " every time the user enters something because it is in the while loop. And yes the "Press:\n\t1 for what you..." is missing – michalis vazaios Jan 06 '18 at 22:06
  • @EricPostpischil:Yes indeed this is a problem, thanks for pointing out. But the point is that the wrong input is a result of not declaring b[3] and not something that occurs after many loops. If I don't declare b[3] the program runs wrong from the beggining – michalis vazaios Jan 06 '18 at 22:09
  • 2
    @michailvazaios: The thing is, you have not shown complete output. You just showed one line that was not what you wanted. But, from looking at the source code, we can see there was more output than that. So we know you omitted something. That makes us wonder what else you omitted. Did you omit other inputs? In other words, were many cases executed before the failure? We do not know, so we have to speculate. It is important to present **complete** information about the problem. – Eric Postpischil Jan 06 '18 at 22:13
  • 2
    Related, if not duplicate: https://stackoverflow.com/questions/15825254/why-is-scanfhhu-char-overwriting-other-variables-when-they-are-local. If you compile with warning `-Wall`, you'll get something like *"warning: unknown conversion type character 'h' in format"*. – Holt Jan 06 '18 at 22:17
  • @Holt: That looks like it could be the answer. – Eric Postpischil Jan 06 '18 at 22:23
  • @EricPostpischil:Whatever is inside the printf is printed correctly.The problem of printing "spider" instead of "manspider" is repeated in the next inputs the same way. If next i press 2 it prints "man" instead of "manman"(or instead of manspiderman if there was a manspider previously) – michalis vazaios Jan 06 '18 at 22:35

3 Answers3

0

You should start by using another way to read from the keyboard, scanf is not ideal when it comes to reading from the keyboard, especially since you only seem to be reading integers.

Using fgets assures you do not have characters left in the buffer that may trigger an accidental additional call to the switch statement and prevents buffer overrun. Since you want to translate the input to an integer do something like this:

char buffer[32];
if (fgets(buffer, sizeof(buffer), stdin) != NULL)
{
  int f = atoi(buffer);  // or sscanf(buffer, "%d", &f);

  switch (f) 
  {...}
}

Instead of using strcpy, strcat use the safer strcpy_s and strcat_s to ensure that the target buffer a has enough size. My guess is you accidentally go beyond the size of a because of scanf causes the switch statement to add more characters than you intended (a debugger would be a better way to solve this problem than my ocular debugging)

e.g.
strcpy_s(a, sizeof(a), "man");

note also that in case 0: you set x to 2 even though string "man" is 3.

AndersK
  • 35,813
  • 6
  • 60
  • 86
  • I wouldn't be so stingy with the buffer... (yes, every `int` will fit), but for another couple-hundred bytes you buy a lot of security. You may also want to check the last char read is `'\n'` to validate a complete line was read and if not handle the error (and discard the remaining characters in `stdin`). Not all compiles adopt libc extension 1, so it is likely `strcpy_s` will not be available except on windoze. – David C. Rankin Jan 07 '18 at 02:49
  • there is no reason to care about \n atoi converts and stops when it does not find any more digits to convert.. for his use case 32 seemed enough, it will not cause a buffer overrun even if he enters more due to length param on fgets. I agree on strcpy_s, could use strncpy instead. – AndersK Jan 08 '18 at 11:58
  • You misunderstood. The `'\n'` check is to validate you read the entire line and a cat didn't step on the keyboard resulting in `1000` characters filling `stdin`. But yes, you are correct on where `atoi` stops (although you should really forget about `atoi` as it provides no way whatsoever to confirm a valid conversion took place. `strtol` is a better option. – David C. Rankin Jan 09 '18 at 03:40
0

This code works correctly:

#include <stdio.h>
#include <string.h>
main(){
char a[100]="man";
printf("A man is bitten by a spider and becomes spiderman.\nSo in this       motive start making stuff.\nTo end the program just click X on top right of the window\n\n");
printf("When you create sth really big, you go back to only having a man.\n\n");
unsigned char x=3,i;
char f=1;
while(1){
    printf("You have a %s\n",a);
    printf("Press:\n\t1 for what you have to bite a spider.\n\t2 for what you have to bite a man.\n\t3 for what you have to bite spiderman.");
    printf("\n\t4 for what you have to get bitten by a spider.\n\t5 for what you have to get bitten by a man.\n\t6 for what you have to get bitten by spiderman.\n\t0 to go from the start\n");
    scanf(" %c",&f);
    switch(f){
       case '0':
        strcpy(a,"man");
        x=3;
        break;
       case '1':
        x+=6;
        if(x<=100){strcat(a,"spider");}
        break;
        case '2':
        x+=3;
        if(x<=100){strcat(a,"man");}
        break;
        case 3:
        x+=9;
        if(x<=100){strcat(a,"spiderman");}
        break;
        case '4':
        x+=6;
        if(x<=100){
            for(i=x;i>=6;i--){
                a[i]=a[i-6];
            }
            a[0]='s';
            a[1]='p';
            a[2]='i';
            a[3]='d';
            a[4]='e';
            a[5]='r';}
        break;
        case '5':
        x+=3;
        if(x<=100){
            for(i=x;i>=3;i--){
                a[i]=a[i-3];
            }
            a[0]='m';
            a[1]='a';
            a[2]='n';}
        break;
        case '6':
        x+=9;
        if(x<=100){
            for(i=x;i>=9;i--){
                a[i]=a[i-9];
            }
            a[0]='s';
            a[1]='p';
            a[2]='i';
            a[3]='d';
            a[4]='e';
            a[5]='r';
            a[6]='m';
            a[7]='a';
            a[8]='n';}
        break;}
    if(x>100){
        strcpy(a,"man");
        x=2;}
        }
}

The problem was with %hhu. By declaring f as a char instead of an unsigned char and doing all the other necessary changes the program runs correctly.

-1

You can try the below code ! The program works perfectly with or without the array 'b[3]' . The main problem is that you use the scanf(),strcpy() & strcat() instead of scanf_s(),strcpy_s() & strcat_s(). I am attaching the screenshot of the output of program.

#include <stdio.h>
#include <string.h>
#include <conio.h>
void main() {
    char a[100] = "man";


    printf("A man is bitten by a spider and becomes spiderman.\n"
        "So in this motive start making stuff.\nTo end the program "
        "just click X on top right of the window\n\n");
    printf("When you create sth really big, you go back to only having "
        "a man.\n\n");
    unsigned char f = 1, x = 3, i;

    while (1){
        printf("You have a %s\n", a);
        /*presentation of the menu*/
        printf("Press:\n"
            "\t1 for what you have to bite a spider.\n"
            "\t2 for what you have to bite a man.\n"
            "\t3 for what you have to bite spiderman.\n"
            "\t4 for what you have to get bitten by a spider.\n"
            "\t5 for what you have to get bitten by a man.\n"
            "\t6 for what you have to get bitten by spiderman.\n"
            "\t0 to go from the start\n");
        scanf_s("%hhu", &f);
        switch (f){
        case 0:
            strcpy_s(a, "man");
            x = 2;
            break;
        case 1:
            x += 6;
            if (x <= 100){
                strcat_s(a, "spider");
            }
            break;
        case 2:
            x += 3;
            if (x <= 100){
                strcat_s(a, "man");
            }
            break;
        case 3:
            x += 9;
            if (x <= 100){
                strcat_s(a, "spiderman");
            }
            break;
        case 4:
            x += 7;
            if (x <= 100){
                for (i = x; i >= 6; i--){
                    a[i] = a[i - 6];
                }
                a[0] = 's';
                a[1] = 'p';
                a[2] = 'i';
                a[3] = 'd';
                a[4] = 'e';
                a[5] = 'r';
            }
            break;
        case 5:
            x += 4;
            if (x <= 100){
                for (i = x; i >= 3; i--){
                    a[i] = a[i - 3];
                }
                a[0] = 'm';
                a[1] = 'a';
                a[2] = 'n';
            }
            break;
        case 6:
            x += 10;
            if (x <= 100){
                for (i = x; i >= 9; i--){
                    a[i] = a[i - 9];
                }
                a[0] = 's';
                a[1] = 'p';
                a[2] = 'i';
                a[3] = 'd';
                a[4] = 'e';
                a[5] = 'r';
                a[6] = 'm';
                a[7] = 'a';
                a[8] = 'n';
            }
            break;
        }
        if (x>100){
            strcpy_s(a, "man");
            x = 2;
        }
    }
    _getch();
}

enter image description here

Usman
  • 1,983
  • 15
  • 28
  • Thanks! It works. The problem was the scanf statement. Ι found that windows implementation of scanf("%hhu",&variablename) has a problem and by making f a char instead of an unsigned one, using %c instead of %hhu and '1' instead of 1 etc the program works correctly – michalis vazaios Jan 07 '18 at 11:28