我在C中写了一个ncurses Scrabble克隆。
我已经写了一些代码来代表一个包,这是一个可以将字符拉出来的洗牌字符的来源,就像在现实生活中从包中拉出随机的瓷砖一样。
我的代码适用于OS X - 但是当我尝试在Debian机器上编译时,它给了我这个直截了当的消息:
~/nscrabble $ ./scrabble
Segmentation fault
我已使用gdb
尝试诊断问题。似乎段错误是由return
语句引起的:
(gdb) run
Starting program: /home/jay/nscrabble/scrabble
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400ca8 in bag () at bag.c:53
53 return b;
(gdb)
你去吧。这是代码(bag.c
和bag.h
)
这是bag.h
-
#ifndef BAG_H_INCLUDED
#define BAG_H_INCLUDED
/*
* This array states how many times each
* letter should show up in the bag.
*
* distributions[0] Number of As
* distributions[1] Number of Bs
* ...
* distributions[25] Number of Zs
* distributions[26] Number of blank tiles
*/
const short distributions[27];
/*
* The bag is the repository of tiles in Scrabble.
* I didn't want to deal with storing pointers
* and freeing them constantly, so I decided to
* store chars.
*/
typedef struct bag {
char tiles[100];
size_t top;
/*
* Get a tile letter out of the bag.
* It removes the letter from the bag.
*/
char (*pop)( struct bag* );
} bag_t;
/*
* The constructor.
* Get a new bag using this.
*/
struct bag bag();
char bg_pop( struct bag* );
#endif
这里bag.c
-
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "bag.h"
const short distributions[27] = {
9, 2, 2, 4, 12, 2, 3, 2, 9, 1, 1, 4, 2, 6, 8, 2, 1,
6, 4, 6, 4, 2, 2, 1, 2, 1, 2
};
char bg_pop( struct bag* b )
{
return b->tiles[b->top--];
}
struct bag bag()
{
struct bag b;
for( char letter = 'A', count = 0; letter <= ']'; letter++ ) {
for(int i = 0; i < distributions[letter - 65]; i++, count++)
b.tiles[count] = letter;
}
srand( time(NULL) );
for( int i = 0; i < 3; i++, rand() )
;
for( int i = 0; i < 98; i++ ) {
int n = (rand() % (100 - i)) + i;
char temp = b.tiles[i];
b.tiles[i] = b.tiles[n];
b.tiles[n] = temp;
}
b.top = 100;
b.pop = bg_pop;
return b;
}
scrabble.c:
#include <stdio.h>
#include "bag.h"
int main( int argc, const char** argv )
{
struct bag b = bag();
for( int i = 0; i < 100; i++ )
printf("%3c", b.tiles[i]);
}
我知道改组正在进行(至少在OS X上)。
有人可以帮助阐明这里发生的事情吗?
答案 0 :(得分:1)
下面:
for( char letter = 'A', count = 0; letter <= ']'; letter++ ) {
for( int i = 0; i < distributions[ letter - 65 ]; i++, count++ ) {
b.tiles[count] = letter;
}
}
如果您打印出count
的值,您会看到它高达152,远高于数组中的100个元素。您似乎是segfaulting,因为这会使count
在您的系统上变为负数,因为您已将其定义为char
,并在您的系统上签名。
你可以将它定义为int
,当我这样做时,segfault就会消失,但是你的数组仍然会超出范围,所以你的逻辑显然有问题{ {1}},在这里。或者,更有用的是,你有一对吐出152个字母的循环,但是你只为其中的100个字节留出了内存,所以你制作的字母多于你有空格的字母。
如果您将count
更改为letter <= ']'
(因为letter <= '['
紧跟在ASCII表格中的'['
之后),那么一旦'Z'
达到100,您的循环就会正确退出,你应该被设置。
答案 1 :(得分:0)
您在第21行超出了数组的范围:
b.tiles[count] = letter;
使用gdb查看此内容:
gdb blah
b 21
cond 1 count >= 100
run
如果您使用上面的count
达到足够高,则会将堆栈中的返回地址废弃,这就是您在return