cstringfor-loopwhile-loopscanf

Why is my string not printing to PowerShell in C on second function call?


I'm a beginner programmer learning C as a hobby. I just learned about accepting user input using scanf() and thought it would be a fun learning experience to make a small "game" that runs in the command prompt or PowerShell. I'm sure there are better ways to accomplish this, but I thought it would be easy to use a string as a visual for the game. The string appears correctly on the first print call, but after attempting to modify the string and reprint it, none of the characters appear.

The basic design I was going for is that scanf() accepts inputs of WASD (one at a time) and moves the player (P) to the new position in the string. (I've also been having problems with multiple inputs, but that is not the focus of this post lol)

I am running Windows10, the compiler I am using is GCC, and I've been using Visual Studio Code to actually write my C files. Here is the code pasted directly from Visual Studio. Please be kind lol. (yes this is also the file where I did hello world and other beginner projects)

#include <stdio.h>
#include <stdbool.h>

struct room{
    int width;
    int height;
    int startX;
    int startY;
    int goalX;
    int goalY;
    int size;
};

int drawRoom(struct room, int, int);
int main(){
    printf("\n==============\n|hello, world|\n==============\n\n");
    struct room room1;
    room1.width = 11;
    room1.height = 11;
    room1.startX = 5;
    room1.startY =9;
    room1.goalX = 5;
    room1.goalY = 1;
    room1.size = (room1.width + 1) * room1.height + 1;

    int playerX = room1.startX;
    int playerY = room1.startY;

    char input;
    bool goalReached = false;

    while(goalReached == false){
        drawRoom(room1, playerX, playerY);
        printf("player position: %d, %d\ngoal position: %d, %d\n", 
            playerX, playerY, room1.goalX, room1.goalY);
        if(playerX == room1.goalX && playerY == room1.goalY){
            printf("You've reached the goal!\n\n");
            goalReached = true;
            continue;
        }
        printf("Enter a direction [WASD]: ");
        scanf("%1s", &input);
        printf("You entered: %c\n\n\n", input);
        if((input == 'w' || input == 'W') && playerY > 1){
            --playerY;
            continue;
        } 
        if((input == 'a' || input == 'A') && playerX > 1){
            --playerX;
            continue;
        }
        if((input == 's' || input == 'S') && playerY < 9){
            ++playerY;
            continue;
        }
        if((input == 'd' || input == 'D') && playerX < 9){
            ++playerX;
            continue;
        }
    }
    return 0;
}

int drawRoom(struct room currentRoom, int xPosition, int yPosition){
    char drawString[currentRoom.size];
    for(int loc = 0; loc < (currentRoom.size); ++loc){
        int x = loc % (currentRoom.width + 1);
        int y = loc / (currentRoom.width + 1);
        if(y == currentRoom.height){
            drawString[loc] = '\0';
            continue;
        } 
        if(x == currentRoom.width){
            drawString[loc] = '\n';
            continue;
        } 
        if(y == 0 || y == currentRoom.height - 1){
            drawString[loc] = '=';
            continue;
        }
        if(x == 0 || x == currentRoom.width - 1){
            drawString[loc] = '|';
            continue;
        }
        if(x == xPosition && y == yPosition){
            drawString[loc] = 'P';
            continue;
        }
        if(x == currentRoom.goalX && y == currentRoom.goalY){
            drawString[loc] = 'G';
            continue;
        }
        drawString[loc] = '.';
    }
    printf("%s\n", drawString);
    return 0;
}

.This is a screenshot from the command prompt, but the same thing happens in PowerShell. As you can see there is space left blank where the string theoretically should be.

My original implementation had everything from the drawRoom() function directly inside the while loop in the main() function.

At first I thought maybe the string was being screwed up some way by the while loop, since it was being declared inside of it. So I tried moving it outside the loop declaring it alongside my input char. When that didn't work, I tried declaring it outside of main altogether with a set length. This also did not work.

Then I thought maybe the fact that I was trying to edit an existing string might be the problem, so I moved it to a separate function. My impression was that because the string is now local to the function, it would be released from memory once the function ends, effectively creating a new, empty string to edit each time the function was called. I may be interpreting this incorrectly. I've also tried declaring the function as an int, char, char*, void; int just happens to be the last one I tried.

The piece that really confuses me is that the PowerShell still leaves a big old gap where the string should theoretically appear. I even looks like it is the right size. I'm wondering if somehow all of my non-whitespace characters are being replaced with whitespace characters, still leaving the newline character \n and end of string character \0 in place. How that would happen is beyond my current knowledge level so I'm unsure how to address it.


Solution

  • char input; and scanf("%1s", &input); are a problem.

    Even though the format string "%1s" scans for only one character, the s tells scanf that a string is being scanned and a terminating zero is appended to input. input only has memory for one character so the appended terminating zero corrupts memory adjacent to input.

    scanf(" %c", &input); tells scanf that only a char is being scanned and no terminating zero is appended. The space before %c tells scanf to scan and discard any whitespace characters.

    The program works as expected when I change the scanf format string from "%1s" to " %c"