PDA

View Full Version : C makes me want to hurt myself (read: Please help me find my seg-fault)


Wyatt
2005-11-16, 09:15
I'm working on a project for my intro programming class, and I'm running into a seg-fault at execution time. My deadline is tonight, but I really need to nail down this problem as quickly as possible. Here is My assignment (http://www.cs.iupui.edu/~cs230/fall05/labs/Project5GameOfLife.html)

Right now I'm running into a seg-fault when I try to print my initial configuration. I'll post the relevant code, and if something jumps out at anybody, please let me know!

First, my function declaration:
int initconfig(char nT[][WIDTH]); /*Prints initial configuration*/

*Note that WIDTH is a preprocessor constant I've defined as 10. HEIGHT is set to 15.

Now my function call from main():
initconfig(&newTable);

And finally, the initconfig function itself:
int initconfig(char nT[][WIDTH]) {
printf("Initial configuration:\n\n");

for (i = 0; i < WIDTH; i++){
for (j = 0; j < HEIGHT; j++) {
printf("%c", &nT[i][j]);
}
}

}

*One final note: initconfig is my function to print the first table after the user inputs the beginning coordinates. The newTable array holds the values of the table (a hyphen for unoccupied cells and an asterisk for occupied cells).

I've made very little progress here. I'm very much in danger of failing this class, and this project is going to have a huge impact. Help!

spotcatbug
2005-11-16, 09:36
int initconfig(char nT[][WIDTH]) {
printf("Initial configuration:\n\n");

for (i = 0; i < WIDTH; i++){
for (j = 0; j < HEIGHT; j++) {
printf("%c", &nT[i][j]);
}
}

}
Right off the bat, I notice that your printf has &nT[i][j]. I think you have i and j reversed.

Wyatt
2005-11-16, 09:39
Right off the bat, I notice that your printf has &nT[i][j]. I think you have i and j reversed.
Nope... I tried it and I actually got the seg-fault faster this time. It's trying to print with i and j where they are. It just prints part of it and then seg-faults out.

ShadowOfGed
2005-11-16, 09:55
I've made very little progress here. I'm very much in danger of failing this class, and this project is going to have a huge impact. Help!

C! My specialty! :D

Here goes:

1. Personally, I'm flabbergasted that your compiler allows the char nT[][WIDTH] construction. It's not good style. In C, typically all array types must have a fixed size, except for the last set of brackets. Thus, char nT[HEIGHT][] would be OK. But if you know the bounds (both HEIGHT and WIDTH) to start with, why not just define the size of both using char nT[HEIGHT][WIDTH]?

2. Your current declaration is for "an array, nT, of unknown length, in which each item contains a pointer to an array of chars of size WIDTH." I'd be concerned that "newTable" is being constructed incorrectly. A seg fault will happen when you try to access memory that you haven't allocated. With your current delcaration, you'd have to manually allocate HEIGHT rows in nT of type char[WIDTH]. Are you doing this?

3. Using &newTable will cause initconfig() to be passed a pointer to the mess that is your newTable construction, which your current initconfig() doesn't handle.

4. Whoa, you really don't understand pointers, do you? :| printf("%c", &nT[i][j]) will pass the memory address (& - the "address-of" operator) of nT[i][j] to printf(), not the character at nT[i][j] like you want. For the record, the ampersand (&) operator returns the memory address of a variable, which is usually used to create a pointer to an existing variable. Example:
int myFunction(int *intPointer);

int main(void)
{
int normalInt;

/* Use & to pass myFunction() a pointer to staticInt */
return myFunction(&normalInt);
}

5. Conversely, to dereference a pointer, you do this:
int myFunction(int normalInt);

int main(void)
{
int firstNormalInt;
int *intPointer;

firstNormalInt = 0;
intPointer = &firstNormalInt;

/* Got to dereference the pointer for myFunction() */
/* It's just my style to always keep pointer dereferencing inside */
/* its own set of parenthesis, as to prevent confusion later. */
return myFunction( (*intPointer) );
}

My suggestions?

/* Define a type here to make your code more readable. */
typedef char[HEIGHT][WIDTH] StatusTable;

/* Pass initconig() a pointer to an existing StatusTable */
int initconfig(StatusTable *nT)
{
/* ... */
printf("%c", (*nT)[i][j]);
/* ... */
}

/* Just as an example */
int main(void)
{
StatusTable newTable;

newTable[0][0] = 'X'; /* again, an example */

initconfig(&newTable);
}

Yeah, your problems sorta stem from terrible mixing of pointers, address-of (ampersand operator), and such. Seg faults almost always stem from trying to access memory you haven't allocated, so when you see a segfault, look for problems with pointers... either accessing memory you haven't allocated (your case, I think), or memory you've already deallocated.

I hope some of this makes sense. Sorry, it's a breach of most honor codes for me to help you much more than this; I purposely didn't read your assignment. But it should be fine for me to help you understand the ins-and-outs of the C language ;) Hopefully I've explained how you're incorrectly using array declarations and pointers... maybe?

Wyatt
2005-11-16, 10:00
Thanks for the suggestions. I'll try to re-work my code as per your suggestions. I'll be back with an update!

ShadowOfGed
2005-11-16, 10:04
Thanks for the suggestions. I'll try to re-work my code as per your suggestions. I'll be back with an update!Oh, and of course with my use of pointers, I failed to include a check in initconfig() to make sure that nT != NULL. But I'm sure you knew to check for that, as it's just good coding style! :) ;)

Kickaha
2005-11-16, 10:15
See? This is why C is evil for large-scale production code. Pointers, addresses, and arrays all intertwining in this incestuous little ball of crap that produces runtime memory faults. :p

Evil, I say.

(Okay, I like C - but it has its place, and that's at the bottom of a system, yakking with the hardware directly.)

Wyatt
2005-11-16, 10:18
See? This is why C is evil for large-scale production code. Pointers, addresses, and arrays all intertwining in this incestuous little ball of crap that produces runtime memory faults. :p

Evil, I say.

(Okay, I like C - but it has its place, and that's at the bottom of a system, yakking with the hardware directly.)
Word. :D

Now our class message board/e-mail system is down. I can't even communicate with my professor or my lab instructors. Bastard technology :p

Damn, I wish I hadn't forgotten to bring my iPod to campus today... I'm damn bored waiting for them to get the system back up. Hopefully our SSH server doesn't go down too...

Wyatt
2005-11-16, 10:29
Okay, I've printed out the thread so I can work in SSH without having to alt-tab every ten seconds... let's see what I can come up with

ShadowOfGed
2005-11-16, 10:34
See? This is why C is evil for large-scale production code. Pointers, addresses, and arrays all intertwining in this incestuous little ball of crap that produces runtime memory faults. :p

Evil, I say.

(Okay, I like C - but it has its place, and that's at the bottom of a system, yakking with the hardware directly.)Maybe it's the control freak in me, but I prefer C and C++ (and possibly Obj-C) to Java, because I like to know exactly what's going on with my memory. If your program leaks memory or has problems with pointers, that's a coding problem, not a shortcoming in the language. Java hides it from people because C proved that a lot of people just can't write code that cleanly deals with memory. So we spend CPU cycles on garbage collection instead. Let's not blame bad programming on the language itself! :p

</soapbox> :smokey:

Yeah yeah, I know that sometimes GC is more efficient because it allocates a pool of memory from the system and then just shifts stuff around inside that, versus allocating/freeing memory all the time. But you could do GC at the kernel level too. "Oh, you want 100 bytes? Well, you've got... 0 right now, so I'll give you 1MB. Then the rest of your allocations will come from that pool until you need more." The only difference is that your pool in C would become fragmented eventually, since it can't rearrange memory locations at that level. But I think most of the efficiency of GC could be matched at the C level, and since you no longer have the overhead of a JVM and all that, it'd probably be comparable. I'm also talking out of my a**, since I'm not yet a kernel-level hacker. ;) :lol:

Kickaha
2005-11-16, 10:47
Instead of rehashing it, I'm just going to point to it: http://forums.appleinsider.com/showthread.php?s=&threadid=57971&highlight=garbage+collection

Have fun. :)

bassplayinMacFiend
2005-11-16, 10:58
"Oh, you want 100 bytes? Well, you've got... 0 right now, so I'll give you 1MB. Then the rest of your allocations will come from that pool until you need more." The only difference is that your pool in C would become fragmented eventually, since it can't rearrange memory locations at that level. But I think most of the efficiency of GC could be matched at the C level, and since you no longer have the overhead of a JVM and all that, it'd probably be comparable. I'm also talking out of my a**, since I'm not yet a kernel-level hacker. ;) :lol:

Isn't this how OS 9 worked? Except you manually allocated the memory pool for each program? Then you had to make sure if you started programs 1, 2 & 3, then quit program 2, you also needed to quit & restart program 3 or else program 4 wouldn't be able to work with the full amount of free RAM because it was fragmented. Or something. I only used OS 9 for about a month, but what I saw of its memory handling I certainly didn't like. :)

[on topic]

I don't think you need the dereference operator (*) in the printf section of this code:
/* Pass initconig() a pointer to an existing StatusTable */
int initconfig(StatusTable *nT)
{
/* ... */
printf("%c", (*nT)[i][j]); // Try printf("%c", nT[i][j]); instead
/* ... */
}

Wyatt
2005-11-16, 11:01
Hopefully I've explained how you're incorrectly using array declarations and pointers... maybe?
I'm beginning to think this is a concept I just can't grasp. I've studied and studied and studied this, but I don't get it. I don't know what the hell is wrong with me.

Koodari
2005-11-16, 11:02
I did read the assignment, and it is written precisely so that you wouldn't need to mess with pointers.

What it doesn't expressly say is if you are supposed to wrap around the edges of the table or stop at the edge for the game of life algorithm. I recommend asking about this rather than guessing.

Don't put the *'s and _'s that are required as output into the array. The data you have there is actually booleans (1-bit values). Considering the algorithm used, using 0 for unoccupied and 1 for occupied would probably be a good idea, so you can just sum the contents of all appropriate array cells. It's also a good idea to #define those two and use the full name wherever you can. When you are supposed to print the table, just translate the 0's and 1's into hyphens and asterisks in the print function. This shows you treat data and its representation as separate.

Also, don't forget to check if the line of input actually is what you expect (two numbers in valid range) before accepting them. If there's a generic way to get bonus points on beginner courses, this is it. ;)

ShadowOfGed said everything else that's necessary.

Wyatt
2005-11-16, 11:07
I did read the assignment, and it is written precisely so that you wouldn't need to mess with pointers.
And I didn't intend to get into this mess. I just don't have time to re-write 135 lines of code before I have to go to work. I only have about 90 minutes to complete this now. However, if I can figure out how to avoid pointers, I will do it.

What it doesn't expressly say is if you are supposed to wrap around the edges of the table or stop at the edge for the game of life algorithm. I recommend asking about this rather than guessing.
I'm not guessing. It says the input and output must be formatted exactly like the example. In the example, the edges are wrapped around.

Don't put the *'s and _'s that are required as output into the array. The data you have there is actually booleans (1-bit values). Considering the algorithm used, using 0 for unoccupied and 1 for occupied would probably be a good idea, so you can just sum the contents of all appropriate array cells. It's also a good idea to #define those two and use the full name wherever you can. When you are supposed to print the table, just translate the 0's and 1's into hyphens and asterisks in the print function. This shows you treat data and its representation as separate.
Good suggestion. I *might* have time to implement this. It would actually even streamline one of my functions quite a bit and make one of my other functions a little easier to execute as well.

Also, don't forget to check if the line of input actually is what you expect (two numbers in valid range) before accepting them. If there's a generic way to get bonus points on beginner courses, this is it. ;)
Already done :)

ShadowOfGed said everything else that's necessary.
If only I understood it... (no offense, ShadowOfGed, I'm just really bad at this, apparently)

ShadowOfGed
2005-11-16, 11:08
Instead of rehashing it, I'm just going to point to it: http://forums.appleinsider.com/showthread.php?s=&threadid=57971&highlight=garbage+collection

Have fun. :)Oh bloody hell, what's this on the table? Worms! :lol:

*tosses the can into the recycling bin* ;)

Nah, my point was that one of the big arguments I'd heard in favor of Java is not so much the GC (which is nice... sometimes), but the fact that your program has a dedicated heap which means that the JVM doesn't have to spend time in kernel space asking for more memory in 100 byte chunks like you do with a C/C++ program... I was only commenting on the CPU cycle benefits of using a pre-allocated heap versus asking for memory in small chunks as needed.

Interesting thread, though. ;)

ShadowOfGed
2005-11-16, 11:38
If only I understood it... (no offense, ShadowOfGed, I'm just really bad at this, apparently)Don't worry, pointers (and references once you get to C++) are pretty much the two hardest concepts to grasp from those languages. Most everyone I know has had trouble with it. For some reason I'm the lucky one and it all makes sense. It might be related to having done some assembly-level stuff where I got to learn how pointers get used/implemented at the processor level. :o

So it's perfectly normal to have a rough start with pointers. I'm just farther along and really lucky to somehow "get it," but it makes it tougher for me to try and explain it to others... I'm sure I could have said it better. If I figure out how to word it more clearly, I'll post again. ;)

ShadowOfGed
2005-11-16, 11:43
I don't think you need the dereference operator (*) in the printf section of this code:Bzzzt! Wrong! ;)

Here's a code snippet where your scenario would work, bassplayinMacFiend:int main(void)
{
StatusTable nT;

nt[0][0] = 'X'; /* whatever, this is just for kicks */

printf("%c", nT[0][0]);

return 0;
}
However, since my example has a StatusTable*, the dereferencing is necessary, a la:int main(void)
{
StatusTable normalTable;
StatusTable *nT;

normalTable[0][0] = 'X';
nT = &normalTable;

printf("%c", (*nT)[0][0]);

return 0;
}
Make sense? Mmmkay, good. :)

Note to self: I really hope I'm correct, 'cause I'd rather not eat crow over statements like "Bzzzt! Wrong!", but I don't have a compiler/command line to validate this right now. :smokey:

Wyatt
2005-11-16, 20:08
Don't worry, pointers (and references once you get to C++) are pretty much the two hardest concepts to grasp from those languages. Most everyone I know has had trouble with it. For some reason I'm the lucky one and it all makes sense. It might be related to having done some assembly-level stuff where I got to learn how pointers get used/implemented at the processor level. :o

So it's perfectly normal to have a rough start with pointers. I'm just farther along and really lucky to somehow "get it," but it makes it tougher for me to try and explain it to others... I'm sure I could have said it better. If I figure out how to word it more clearly, I'll post again. ;)
Thanks for the encouragement. Hopefully I won't fail this class as a result of this project. It's a very far outside possibility, but it is a possibility. The project is due tonight, but I don't think there's anything else I can do with it without somebody actually directly helping me. I'll see if I can get some help tomorrow and maybe get partial credit for it. If not, then I want to fix it just so I can figure out what the hell I'm doing wrong. Thanks again for all your input.

Koodari
2005-11-17, 09:43
When you have trouble with pointers, draw a picture of what you think the structure should be. This is the best help when the pointers are part of a larger data structure, and you are constructing it wrong in the code.

The other thing to do is to go step by step through where you pass addresses into functions, any place you manipulate pointers. At any sight of * or &, or start of a function, stop and make sure the type is what you expect.

scratt
2005-11-17, 10:35
(Okay, I like C - but it has its place, and that's at the bottom of a system, yakking with the hardware directly.)

Well.. C doesn't actually do that. It's compiled into 'machine code'. Something you young whipper snappers have never heard of.. :p

Kickaha
2005-11-17, 10:48
:lol: Post-Apple ][, my first computer experience of note was building one. Not from a motherboard, CPU, and drive, but from diodes, transistors, and a Motorola 68000 CPU. Had a whopping 1K of RAM, a hexadecimal input keypad, and 8 numeric LED readout. It was required to get a physics degree at UW, because you were expected to know how to build your own custom lab equipment. I had the most fun with that thing - we had to come up with a project to have it interact with the real world, so my lab partner hooked a sonic range finder into it and stored the data in RAM. I then wrote a program to find derivatives across the data, and the distance, velocity, and acceleration could then be displayed on an oscilloscope in X/Y mode.

I <3 (clean) assembly. :)

scratt
2005-11-17, 10:54
:lol: Post-Apple ][, my first computer experience of note was building one. Not from a motherboard, CPU, and drive, but from diodes, transistors, and a Motorola 68000 CPU. Had a whopping 2K of RAM, a hexadecimal input keypad, and 8 numeric LED readout. It was required to get a physics degree at UW, because you were expected to know how to build your own custom lab equipment. I had the most fun with that thing - we had to come up with a project to have it interact with the real world, so my lab partner hooked a sonic range finder into it and stored the data in RAM. I then wrote a program to find derivatives across the data, and the distance, velocity, and acceleration could then be displayed on an oscilloscope in X/Y mode.

I <3 (clean) assembly. :)

Sweet! Good comback! I like it!

Ahh but my favorite assembler was 6502..

I remember much later when I was working on prototypes 68030 which cost just silly money each (as they weren't mass produced) even then I though assembler was just getting too darn complex!

I've never delved into x86 as that was just plain wierd from the first 'till the last time I saw it... Always thought the 680x0 series were more 6502 like..

So I pushed off to program V60s and things like that in Japan... Nothing like shovelling models into a graphics pipeline with a whizzy little processor.. Happy Days! ;)

Kickaha
2005-11-17, 11:18
Wheee! Have you ever taken a gander at the PPC assembly definition? *CLEAN* It managed to maintain the simplicity of something like the 680x0 line while providing much more power. Amazing bit of work.

Ah well, those days are behind us... :}

I'm hoping the new GPGP (General Purpose use of Graphical Processors) push will kickstart a new generation of assembly rats. :)

Because it really frightens me when I look at the graduate students we get in CS, and they not only have never played in assembly, or built their own circuitboard, but don't even know how a transistor works. Hell, most of them haven't a clue how a *COMPILER* works. :p *sigh* Kids these days.

scratt
2005-11-17, 11:24
*reclines in big red silk armchair*

*puffs on cigar and sips his whiskey*

*doffs his hat to Dr. Kick*

Absolutely my dear Dr. :)