简体   繁体   中英

Segmentation fault when initializing struct w/ arrays

I'm writing an ncurses Scrabble clone in C.

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:

~/nscrabble $ ./scrabble
Segmentation fault

I've used gdb to try to diagnose the problem. It appears that the segfault was caused on the return statement:

(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 --

#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 --

#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]);
}

I know that the shuffling is being done correctly (at least on 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. 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.

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. 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.

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.

You are exceeding the bounds of your array at line 21:

b.tiles[count] = letter;

To see this with 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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