简体   繁体   English

初始化带有数组的结构时出现分段错误

[英]Segmentation fault when initializing struct w/ arrays

I'm writing an ncurses Scrabble clone in C. 我正在用C写ncurses Scrabble克隆。

I've written some code to represent a bag, which is a source of shuffled characters that you can pull characters out of, much like pulling random tiles out of a bag in real life. 我已经编写了一些代码来表示袋子,这是可以将字符拖出的乱序字符的来源,就像在现实生活中从袋子中随机抽出瓷砖一样。

My code works on OS X - but when I try to compile on a Debian machine, it gives me this blunt message: 我的代码可以在OS X上运行-但是,当我尝试在Debian机器上进行编译时,它给了我这个直截了当的消息:

~/nscrabble $ ./scrabble
Segmentation fault

I've used gdb to try to diagnose the problem. 我已经使用gdb尝试诊断问题。 It appears that the segfault was caused on the return statement: 似乎段错误是在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) 

There you go. 妳去 Here's the code (both bag.c and bag.h ) Here's bag.h -- 这是代码( bag.cbag.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

And here's bag.c -- 这是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: 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]);
}

I know that the shuffling is being done correctly (at least on OS X). 我知道改组是正确完成的(至少在OS X上是这样)。

Could someone please help shed some light as to what is happening here? 有人可以帮忙弄清楚这里发生的事情吗?

Here: 这里:

for( char letter = 'A', count = 0; letter <= ']'; letter++ ) {
    for( int i = 0; i < distributions[ letter - 65 ]; i++, count++ ) {
        b.tiles[count] = letter;
    }
}

if you print out the value of count you'll see that it gets as high as 152, way higher than the 100 elements in your array. 如果您打印出count的值,您会发现它的值高达152,远高于数组中的100个元素。 You seem to be segfaulting because this will make count go negative on your system, as you've defined it as a char , which is signed on your system. 您似乎正在断断续续,因为这会使系统中的count变为负数,因为您已将其定义为在系统上签名的char

You can define it as an int and the segfault goes away for me when I do, but you're still going way out of bounds on your array, so there's clearly something wrong with your logic in using count , here. 您可以将其定义为int ,当我这样做时,segfault对我来说就消失了,但是您仍然无法超出数组的范围,因此使用count的逻辑显然存在问题。 Or, more usefully, you've got a pair of loops which spit out 152 letters, but you've only set aside memory for 100 of them, so you're making more letters than you have space for. 或者,更有用的是,您有一对循环,可吐出152个字母,但您只为其中的100个预留了内存,因此您制作的字母多于空间。

If you change letter <= ']' to letter <= '[' (since '[' comes immediately after 'Z' in the ASCII table) then your loop correctly quits once count reaches 100, and you should be set. 如果将letter <= ']'更改为letter <= '[' (因为ASCII表中的'['紧跟在'Z'之后),则一旦count达到100,循环就正确退出,应该进行设置。

You are exceeding the bounds of your array at line 21: 您超出了第21行的数组范围:

b.tiles[count] = letter;

To see this with gdb: 要在gdb中看到此内容:

gdb blah
b 21
cond 1 count >= 100
run

If you go high enough with count above, you'll trash the return address on the stack and that's why you segfault on the return 如果你去高足以与count上面,你会在堆栈上垃圾的返回地址,这就是为什么你在段错误的return

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM