Thread: Seg fault

  1. #1
    Registered User Tommo's Avatar
    Join Date
    Jun 2007
    Location
    Scotland
    Posts
    101

    Seg fault

    Hi.

    I am getting a Seg fault and I don't know why.

    Basically, in blackjack, I have a hand of cards and I am trying to sum up the hand:

    Code:
    struct card_t {
    	unsigned short int card;  /* Ace-King (1-13) */
    	unsigned short int suit;  /* Clubs,Diamonds,Hearts,Spades (1-4) */
    };
    
    int main(void) {
      ....
    
      printf("mycards score = %d\ncompscards score = %d\n", sum_up_hand( mycards ), sum_up_hand( compscards ) );
    
     ......
    }
    
    unsigned short int 
    sum_up_hand( struct card_t *hand ) {
    
    	int i = 0;
    	unsigned short int total = 0;
    	while( (hand + i) != NULL ) {
    		total += value_of_card( (hand + i)->card );
    		i++;
    	}
    	
    	return total;
    
    }
    
    unsigned short int
    value_of_card( unsigned short int n ) {
    
    	int i, value = 0;
    	for(i = 0; i < 10; i++) {
    		/* card ace corresponds to i=0, card 2 corresponds to i=1, and so on until i=9*/
    		value = ( n == i ) ? i + 1 : 0;
    	}
    
    	switch( n ) {
    	
    		case 10: //jack
    		  value = 10;
    		  break;
    		case 11: // queen
    		  value = 10;
    		  break;
    		case 12:  //king
    		  value = 10;
    		  break;
    
    	}
    
    	return value;
    
    }
    Above is just the necessary code, well hopefully. Compiles ok, I go to run it and receive a Seg fault. Any idea? I know I'm trying to access something which doesn't belong to me, but I don't know what.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > while( (hand + i) != NULL )
    Well this isn't going to be true for a long while, not until the address wraps round to NULL.
    In the mean time, any invalid address will segfault.

    How about a for loop which counts through at most 52 cards?

    Also, using &#37;d to print an unsigned short is also problematic.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User Tommo's Avatar
    Join Date
    Jun 2007
    Location
    Scotland
    Posts
    101
    Hmm I'm not sure about the for loop. Seems unnecessary to loop more than is needed. There must be a way to stop when it comes to an uninitialised value?

    Code:
    for(i=0;i<52;i++) {
    		total += value_of_card( (hand + i)->card );
    }
    Wont I get garbage for 'total', as memory is filled with garbage initially? I suppose I could set every value to -1 and loop until it hits a -1? (And remove the unsigned obviously). What would you suggest?

    About the %d, you're right; I couldn't find a flag for short, so assuming there isn't one? Will I just cast (int) to the argument then in that case?

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    %hd is for short.

    And as for checking for invalid, how about
    Code:
    struct card_t {
            unsigned char isValid;  /* 1 is valid, 0 is not */
    	unsigned short int card;  /* Ace-King (1-13) */
    	unsigned short int suit;  /* Clubs,Diamonds,Hearts,Spades (1-4) */
    };
    Or if hands are always the same size, maybe
    sum_up_hand( struct card_t *hand, size_t numCardsInHand )
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Chinese pâté foxman's Avatar
    Join Date
    Jul 2007
    Location
    Canada
    Posts
    404
    I guess what you mean was
    Code:
    while( *(hand + i) != NULL ) // same as hand[i] != NULL
    Better way to implement your function would be to add an extra argument telling the number of element to check
    Code:
    unsigned short int 
    sum_up_hand(struct card_t *hand, int nbOfCards )
    There's also different ways of doing this...


    And your function value_of_card seems overly complicated. Also, i don't know if you realized that this loop
    Code:
    for(i = 0; i < 10; i++)
    {
    	value = ( n == i ) ? i + 1 : 0;
    }
    was in fact equivalent to this
    Code:
    value = (n == 9) ? 10 : 0;
    i = 10;
    As for this
    Code:
    switch( n ) {
    	
    		case 10: //jack
    		  value = 10;
    		  break;
    		case 11: // queen
    		  value = 10;
    		  break;
    		case 12:  //king
    		  value = 10;
    		  break;
    
    	}
    could be replaced with this
    Code:
    if (n >= 10)
    	value = 10;

    And by the way, the format specifier for unsigned variable is &#37;u, whatever it's an unsigned char, short or int. But i'm not sure this would have lead to incorrect output, since an unsigned short promoted to an (signed/unsigned) int wouldn't have mess with the sign bit of the int, in the case int is of larger size than short. But i'm not 100% sure.

  6. #6
    Chinese pâté foxman's Avatar
    Join Date
    Jul 2007
    Location
    Canada
    Posts
    404
    Oh and by the way there's a difference between an "uninitialised value" an the NULL value. If one variable has the NULL value it is because it has been initialised to the NULL value.

  7. #7
    Registered User Tommo's Avatar
    Join Date
    Jun 2007
    Location
    Scotland
    Posts
    101
    Sorry, I did make a fair amount of foolish mistakes. New functions:
    Code:
    unsigned short int 
    sum_up_hand( struct card_t *hand , unsigned short int no_of_cards ) {
    
    	int i;
    	unsigned short int total = 0;
    
    	for(i = 0 ;i < no_of_cards;i++) {
    		total += value_of_card( (hand + i)->card );
    	}
    	
    	return total;
    
    }
    
    unsigned short int
    value_of_card( unsigned short int n ) {
    
    	int value = 0;
    	if( n < 10 ) {
    		value = n+1;
    	}
    
    	if( n >= 10 )
    		value = 10;
    
    	return value;
    
    }
    Code:
    while( *(hand + i) != NULL ) // same as hand[i] != NULL
    That is indeed what i meant. D'oh.
    Code:
    for(i = 0; i < 10; i++)
    {
    	value = ( n == i ) ? i + 1 : 0;
    }
    Yes, i see it now, thanks. Pesky 0.
    %hd is for short.
    Thanks, I missed that.
    Thank you foxman and Salem, much appreciated.

  8. #8
    Registered User
    Join Date
    Oct 2001
    Posts
    2,129
    Quote Originally Posted by foxman View Post
    And by the way, the format specifier for unsigned variable is &#37;u, whatever it's an unsigned char, short or int. But i'm not sure this would have lead to incorrect output, since an unsigned short promoted to an (signed/unsigned) int wouldn't have mess with the sign bit of the int, in the case int is of larger size than short. But i'm not 100% sure.
    Code:
    int printf(const char * format, ... );
    it wouldn't be cast because the compiler wouldn't know what to cast it to.
    Last edited by robwhit; 08-24-2007 at 11:40 AM.

  9. #9
    Chinese pâté foxman's Avatar
    Join Date
    Jul 2007
    Location
    Canada
    Posts
    404
    Well i wasn't talking about cast, but more about promotion, because, like you mentionned, the called function doesn't know the type of the argument so i tought C was maybe putting in place the char->short->int and float->double promotion in this case.

    Because i'm sure you already saw those kind of code working perfectly well
    Code:
    char c = 'a';
    unsigned int i = 0xFF0000FF;
    
    printf("ASCII code of 'a' is %d, and i have %u things", c, i);
    But that's it, i don't know exactly how are working function with varying number of additional arguments (even if i have some ideas). I looked a bit on the net but found nothing really explicit. I still found this, who let me believe i'm right. That's it, promotion is happening in those case, for variable of type char, short (to int) or float (to double).

  10. #10
    Registered User
    Join Date
    Oct 2001
    Posts
    2,129
    the thing about variable argument lists is that on type information is not described in it to the compiler. so it cannot perform promotion on those variables. the printf function does it internally, with casts from the data provided in the char * format string. Without that, it would be completely clueless. and easy to get wrong. so compilers sometimes have extra checks for the crt functions that use vargs so that you don't trip up so often. but other than that, it's completely clueless. in fact, it can ........ things up.
    Code:
    #include <stdio.h>
    
    int main(void)
    {
    	printf("&#37;c ", 10000000);
    
    	return 0;
    }
    Code:
    C:\>gcc -std=c99 -Wall -Werror -pedantic main.c
    
    C:\>a
    &#199;
    C:\>
    edit: I just remembered you were talking about promotion, not the other way around, but the idea is the same. the compiler has to know what the types are to do promotion.

    edit2:
    9 If a conversion specification is invalid, the behavior is undefined.242) If any argument is
    not the correct type for the corresponding conversion specification, the behavior is
    undefined.
    Last edited by robwhit; 08-24-2007 at 03:27 PM.

  11. #11
    Chinese pâté foxman's Avatar
    Join Date
    Jul 2007
    Location
    Canada
    Posts
    404
    What i meaned is that there is promotion BEFORE the function (the one with the variable arguments list) is called, and it's the "promoted" version of the values who are passed to the function. The compiler does know the type of the arguments you are passing . But the called function won't know.

    Well, for things to be clear, what i mean is that if you write something like this
    Code:
    char c = 'a';
    printf("%d", c);
    well the compiler will add some instructions (promoting char to int) so it's exactly like you wrote this
    Code:
    char c = 'a';
    printf("%d", (int) c);

  12. #12
    Registered User
    Join Date
    Oct 2001
    Posts
    2,129
    how would it know you want it converted to an int?

  13. #13
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,005
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

  14. #14
    Registered User
    Join Date
    Oct 2001
    Posts
    2,129
    oh ok, I guess I was wrong.
    thanks Dave_Sinkula.

  15. #15
    Registered User Tommo's Avatar
    Join Date
    Jun 2007
    Location
    Scotland
    Posts
    101
    Sorry to digress, but I completed the blackjack game. Any advice/suggestions/improvements would be appreciated. Thanks

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Getting a seg fault
    By ammochck21 in forum C Programming
    Replies: 11
    Last Post: 01-23-2009, 05:27 AM
  2. Seg Fault in Compare Function
    By tytelizgal in forum C Programming
    Replies: 1
    Last Post: 10-25-2008, 03:06 PM
  3. seg fault at vectornew
    By tytelizgal in forum C Programming
    Replies: 2
    Last Post: 10-25-2008, 01:22 PM
  4. weird seg fault
    By Vermelho in forum C Programming
    Replies: 3
    Last Post: 05-10-2008, 08:27 PM
  5. Seg Fault Problem
    By ChazWest in forum C++ Programming
    Replies: 2
    Last Post: 04-18-2002, 03:24 PM