2

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.

9
  • 1
    I assume that you run your C program from a PowerShell terminal window. If that is so then the PowerShell window is simply your console and your question has nothing to do with PowerShell. Hence I think you should change the title of your question as it was confusing for me and I'm guessing will probably confuse others as well. As I understand it, your question is about your C program writing to stdout. Commented Jul 22 at 5:44
  • 1
    Please try to create a minimal reproducible example to show us. With emphasis on the minimal part. Commented Jul 22 at 5:51
  • 2
    Also, remember that strings in C are arrays of characters plus a null terminator. If you try to use an array of characters that doesn't include the null terminator, then it leads to undefined behavior. Commented Jul 22 at 5:53
  • For one of the next versions of your game ==> try ncurses. Commented Jul 22 at 10:28
  • C may be a hobby for you, but it looks like you aren't new to programming. With that being the case, it may come as a surprise to you how few guard rails C provides. The C programmer has a great deal of responsibility for writing correct code, and C doesn't make many guarantees about what happens when they make errors. In many cases where Python on Java (say) would promise an exception, a C program simply produces undefined behavior, which can manifest as an error message or program crash, but oftentimes manifests more subtly. Sometimes even as the behavior you expected. Commented Jul 22 at 12:26

1 Answer 1

2

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"

Sign up to request clarification or add additional context in comments.

1 Comment

This worked for me as well! Thank you very much!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.