2016-11-11 4 views
1

C에서 간단한 텍스트 모험 프로그램을 작성하려고합니다. 각 방의 이름/설명을 설정할 때 strcpy()에 문제가 있습니다. 게임 (room_setup() 참조). 처음 두 (NO_ROOM 및 KITCHEN)를 제외한 모든 객실의 이름/설명을 설정합니다. 간단한 테스트로 일부 문자열에서는 strcpy()가 작동하지 않지만 다른 문자열에서는 작동하지 않습니다.

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

#define DIRS 4 
#define DEBUG 0 
#define MAX_INPUT_LENGTH 100 

// defines numeric values for each direction 
typedef enum {NORTH, EAST, SOUTH, WEST} en_dirs; 

// defines numeric values for each room 
typedef enum { 
    KITCHEN, 
    PANTRY, 
    HALLWAY_1, 
    HALLWAY_2, 
    TROLLS_DOMAIN, 
    EMPTY_ROOM_1, 
    EMPTY_ROOM_2, 
    EXIT, 
    NO_ROOM 
} en_rooms; 

// defines numeric values for each item 
typedef enum{ 
    APPLE, 
    KEY, 
    NO_ITEM 
} en_items; 

// defines a struct type to store room data 
typedef struct room{ 
    char name[100]; 
    char desc[100]; 
    en_dirs around[DIRS]; 
} Room; 

// defines a struct type to store item data 
typedef struct items{ 
    char name[100]; 
    char desc[100]; 
} Item; 

void str_read(char *s);  // read string from console, point s to it 
void str_upper(char *s); // convert string to upper case 
void room_setup(Room *r); // fill info about rooms into r array 
void item_setup(Item *i); // fill info about items into i array 

int main(void){ 
    char input[MAX_INPUT_LENGTH]; 
    char *verb, *noun; 

    // arrays to store room and item info. NO_**** is always the final element 
    // in their respective enums, so the size of the array will never be larger 
    // than necessary. 
    Room rooms[NO_ROOM]; 
    Item items[NO_ITEM]; 

    room_setup(rooms); // fill rooms array with info 
    item_setup(items); // fill items array with info 

    en_rooms currentRoom = KITCHEN; // set the starting room to the kitchen 

    // main game loop 
    while(1){ 

     // print current room name + description 
     printf("-- %s --\n", rooms[currentRoom].name); 
     printf("%s\n", rooms[currentRoom].desc); 

     printf("\n> "); 

     // read input and convert it to upper case 
     str_read(input); 
     str_upper(input); 

     if(DEBUG){ 
      printf("Input: %s\n", input); 
      printf("Length: %d\n", strlen(input)); 
     } 

     // split input into two pieces (expects max of two words, for now) 
     verb = strtok(input, " "); 
     noun = strtok(NULL, " "); 

     if(DEBUG){ 
      printf("Verb: %s\n", verb); 
      printf("Noun: %s\n", noun); 
     } 

     /* 
     if(strcmp(input, "NORTH") == 0 && rooms[currentRoom].around[NORTH] != NO_ROOM){ 
      currentRoom = rooms[currentRoom].around[NORTH]; 
     } 

     */ 

    } 

    return 0; 
} 

// points s to new string. clears stdin if user has input more than 
// MAX_USER_INPUT characters. 
void str_read(char *s){ 
    fgets(s, MAX_INPUT_LENGTH, stdin); // point s to user input from stdin 

    // clear extra characters from stdin, if the user has input more than 
    // MAX_INPUT_LENGTH characters. 
    if(!strchr(s, '\n')){ // newline does not exist 
     while(fgetc(stdin) != '\n'); // discard until newline 
    } 
} 

// converts string s to upper case 
void str_upper(char *s){ 
    int i; 
    char c; 

    for(i = 0; i < strlen(s); i++){ 
     s[i] = toupper(s[i]); 
    } 
} 

// fills the array r with info on each room. 
void room_setup(Room *r){ 

    strcpy(r[NO_ROOM].name, "Nothing there."); 
    strcpy(r[NO_ROOM].name, "Description"); 
    r[NO_ROOM].around[NORTH] = NO_ROOM; 
    r[NO_ROOM].around[EAST] = NO_ROOM; 
    r[NO_ROOM].around[SOUTH] = NO_ROOM; 
    r[NO_ROOM].around[WEST] = NO_ROOM; 

    strcpy(r[KITCHEN].name, "Kitchen"); 
    strcpy(r[KITCHEN].desc, "This is the kitchen."); 
    r[KITCHEN].around[NORTH] = NO_ROOM; 
    r[KITCHEN].around[EAST] = PANTRY; 
    r[KITCHEN].around[SOUTH] = NO_ROOM; 
    r[KITCHEN].around[WEST] = NO_ROOM; 

    strcpy(r[HALLWAY_1].name, "Hallway"); 
    strcpy(r[HALLWAY_1].desc, "A long hallway."); 
    r[HALLWAY_1].around[NORTH] = HALLWAY_2; 
    r[HALLWAY_1].around[EAST] = NO_ROOM; 
    r[HALLWAY_1].around[SOUTH] = KITCHEN; 
    r[HALLWAY_1].around[WEST] = TROLLS_DOMAIN; 

    strcpy(r[TROLLS_DOMAIN].name, "Troll's Domain"); 
    strcpy(r[TROLLS_DOMAIN].desc, "You see a Troll."); 
    r[TROLLS_DOMAIN].around[NORTH] = NO_ROOM; 
    r[TROLLS_DOMAIN].around[EAST] = HALLWAY_1; 
    r[TROLLS_DOMAIN].around[SOUTH] = EMPTY_ROOM_1; 
    r[TROLLS_DOMAIN].around[WEST] = NO_ROOM; 

    strcpy(r[EMPTY_ROOM_1].name, "Empty Room"); 
    strcpy(r[EMPTY_ROOM_1].desc , "An empty room. There was no reason to come here."); 
    r[EMPTY_ROOM_1].around[NORTH] = TROLLS_DOMAIN; 
    r[EMPTY_ROOM_1].around[EAST] = NO_ROOM; 
    r[EMPTY_ROOM_1].around[SOUTH] = NO_ROOM; 
    r[EMPTY_ROOM_1].around[WEST] = NO_ROOM; 

    strcpy(r[HALLWAY_2].name, "Hallway"); //hallway 2 
    strcpy(r[HALLWAY_2].desc, "A long hallway."); 
    r[HALLWAY_2].around[NORTH] = EXIT; 
    r[HALLWAY_2].around[EAST] = EMPTY_ROOM_2; 
    r[HALLWAY_2].around[SOUTH] = NO_ROOM; 
    r[HALLWAY_2].around[WEST] = NO_ROOM; 

    strcpy(r[EMPTY_ROOM_2].name, "Empty Room"); 
    strcpy(r[EMPTY_ROOM_2].desc , "An empty room."); 
    r[EMPTY_ROOM_2].around[NORTH] = NO_ROOM; 
    r[EMPTY_ROOM_2].around[EAST] = NO_ROOM; 
    r[EMPTY_ROOM_2].around[SOUTH] = NO_ROOM; 
    r[EMPTY_ROOM_2].around[WEST] = HALLWAY_2; 

    strcpy(r[EXIT].name, "Exit"); 
    strcpy(r[EXIT].desc, "You win lol"); 
    r[EXIT].around[NORTH] = NO_ROOM; 
    r[EXIT].around[EAST] = NO_ROOM; 
    r[EXIT].around[SOUTH] = HALLWAY_2; 
    r[EXIT].around[WEST] = NO_ROOM; 

} 

// fills the array i with info on each item. 
void item_setup(Item *i){ 
    strcpy(i[APPLE].name, "Apple"); 
    strcpy(i[APPLE].desc, "A bright red apple."); 

    strcpy(i[KEY].name, "Key"); 
    strcpy(i[NO_ITEM].name, "A silver key."); 

    strcpy(i[NO_ITEM].name, ""); 
    strcpy(i[NO_ITEM].desc, ""); 
} 

, 나는 while 루프 동안 currentRoom 증가를 만들고,이 출력을했다 :

-- -- 


> 
-- -- 


> 
-- Hallway -- 
A long hallway. 

> 
-- Hallway -- 
A long hallway. 

> 
-- Troll's Domain -- 
You see a Troll. 

> 
-- Empty Room -- 
An empty room. There was no reason to come here. 

> 
-- Empty Room -- 
An empty room. 

> 
-- Exit -- 
You win lol 

NO_ROOM과 부엌이 보인다 구조체에 복사 자신의 정보를 없었어요. 누구든지 제가 잘못 가고있는 곳에서 운동 할 수있게 도와 줄 수 있습니까?

+3

"일부 문자열에서는 strcpy()가 작동하지 않지만 다른 문자열에서는 작동하지 않습니다"- 그래서 어떤 문자열에서도 작동하지 않습니까? 또는 그것이 작동하는 방법을 알았 으면 문자열에서 작업 중일 수 있습니까? 나는 다른 정보와 함께 [ask]가 요구하는대로 [mcve]라는 코드의 벽을 볼 수 있습니다. – Olaf

+1

코드를 컴파일해서는 안됩니다. 'around' 멤버는'en_dirs' 타입이지만'en_rooms'을 가지고 있습니다. –

+0

@DavidSchwartz 지적 해 주셔서 감사합니다. 하지만 슬프게도 여전히 'en_rooms'로 바뀌면 똑같은 문제가 발생합니다. – Sato

답변

2

부족 버퍼 크기 - 오프 같은 1

// Room rooms[NO_ROOM]; 
Room rooms[NO_ROOM + 1]; 

이상

typedef enum { 
    KITCHEN, 
    PANTRY, 
    ... 
    NO_ROOM, 

    // Insure ROOM_N is 1 greater than all the others. 
    // Putting it last usually does this. 
    ROOM_N 
} en_rooms; 

Room rooms[ROOM_N]; 

에 의해 Item items[NO_ITEM];

가능성이 다른 문제에.

+0

감사합니다. 다른 문제가 많습니다. 예 / – Sato

2

우리는 이것을 가지고 :

typedef enum{ 
    APPLE,  // 0 
    KEY,  // 1 
    NO_ITEM // 2 
} en_items; 

좋아, NO_ITEM는 2입니다 그리고 우리는이 있습니다

Item items[NO_ITEM]; 

좋아, items이 두 항목의 배열입니다. 그리고 우리는이 있습니다

strcpy(i[APPLE].name, "Apple"); 
strcpy(i[APPLE].desc, "A bright red apple."); 

strcpy(i[KEY].name, "Key"); 
strcpy(i[NO_ITEM].name, "A silver key."); 

strcpy(i[NO_ITEM].name, ""); 
strcpy(i[NO_ITEM].desc, ""); 

그래서 우리는 두 항목의 배열을 가지고 있고, 우리는 그 중 세 가지를 모두 초기화하는 것입니다. 죄송합니다.