Thread: segmentation fault

  1. #1
    Registered User
    Join Date
    Jun 2011
    Posts
    5

    segmentation fault

    Hi All,
    i'm pretty new to C programming.
    In the following i will put the first program i wrote.
    If i try to open a file named "bruco.coord" containing a few lines with number the code works fine.
    If i try to open named "bruco.coord" containing 81Milions of lines the code gives me the error "segmentation fault".
    In both cases structure of bruco.coord is something like

    1 4
    2 5
    5 8
    and so on...

    Here is my code, any idea on how to solve the problem ?

    Thanks,
    Andrea

    Code:
    #include <stdio.h>
    #include <string.h>
    
    
    int main ( void )
    {
    char filename[] = "bruco.coord";
    FILE *file ;
    file= fopen (filename,"r");
    if ( file != NULL )
    {
    char line [8260000]; /* or other suitable maximum line size */
    float step=-0.4;
    int i;
    float min=-0.02;
    float max=0.02;
    float a[10000];
    float limit1;
    float limit2;
    while ( fgets ( line, sizeof line, file ) != NULL ) /* read a line */
    {
    sscanf(line,"%f%f", &limit1, &limit2);
    
    if (limit2==11111111)
    {
    
    int indice0=0;
    float maxval=0;
    float minval=0;
    for (indice0 = 0 ; indice0 < i ; indice0++)
    {
    if (a[indice0] > maxval)
    {
    maxval = a[indice0] ;
    }
    }
    
    for (indice0 = 0 ; indice0 < i ; indice0++)
    {
    if (a[indice0] < minval)
    {
    minval = a[indice0];
    }
    }
    int passo=0;
    float bin_center[10000];
    int indice2=0;
    int freq_count[10000];
    float freqsize=1000;
    float bin_size=(maxval - minval)/freqsize;
    for (passo=0; passo<freqsize; passo++)
    {
    for (indice2 = 0; indice2 < i ; indice2++)
    {
    if ((a[indice2]>minval+passo*bin_size)&(a[indice2]<minval+(passo+1)*bin_size))
    {
    freq_count[passo]++;
    bin_center[passo]=minval+passo*bin_size;
    }
    else if ((a[indice2]<minval+passo*bin_size))
    {
    bin_center[passo]=minval+passo*bin_size;
    }
    else if ((a[indice2]>minval+(passo+1)*bin_size))
    {
    bin_center[passo]=minval+passo*bin_size;
    }
    }
    }
    int ciao=0;
    for (ciao=0; ciao<freqsize; ciao++)
    {
    printf("%f %f %i\n",step, (bin_center[ciao]*57.32-step), freq_count[ciao]);
    FILE *destinazione;
    destinazione = fopen("file.txt","a+"); /* apend file (add text to a file or create a file if it does not exist.*/
    fprintf(destinazione,"%f %f %i\n",step, (bin_center[ciao]*57.32-step), freq_count[ciao]); /*writes*/
    fclose(destinazione); /*done!*/
    }
    memset(a, 0, i);
    memset(freq_count, 0, i);
    memset(bin_center, 0, i);
    i=0;
    step=step+0.01;
    
    }
    /* conto il numero di elementi che mi interessa binnare */
    else if ((limit2<max)&(limit2>min))
    {
    a[i] = limit2;
    i++;
    }
    /* fine del conteggio */
    }
    fclose ( file );
    }
    else
    {
    perror ( filename ); /* why didn't the file open? */
    }
    return 0;
    }

  2. #2
    Registered User
    Join Date
    May 2009
    Posts
    4,183
    You need to indent your code so it is readable.
    You are using "&" instead of "&&" as the logical and in two if statements.

    Tim S.

  3. #3
    Registered User
    Join Date
    Jun 2011
    Posts
    5
    ok, i repost the code.

    Thanks for suggestion about "&", but it did not solved.

    Andrea



    Code:
    #include <stdio.h>
    #include <string.h>
        
    
        int main ( void )
        {
        char filename[] = "bruco.coord";
        FILE *file ;
        file= fopen (filename,"r");
        if ( file != NULL )
        {
        char line [8260000]; /* or other suitable maximum line size */
        float step=-0.4;
        int i;
        float min=-0.02;
        float max=0.02;
        float a[10000];
        float limit1;
        float limit2;
        while ( fgets ( line, sizeof line, file ) != NULL ) /* read a line */
        {
    		sscanf(line,"%f%f", &limit1, &limit2);
    	
    		if (limit2==11111111)
    		{
    								
    				int indice0=0;				
    				float maxval=0;
    				float minval=0;
    				for (indice0 = 0 ; indice0 < i ; indice0++) 
    				{
    					if (a[indice0] > maxval) 
    					{
    						maxval = a[indice0] ;
    					}
    				}
    				
    				for (indice0 = 0 ; indice0 < i ; indice0++) 
    				{
    					if (a[indice0] < minval) 
    					{
    						minval = a[indice0];
    					}
    				}
    			int passo=0;
    			float bin_center[10000];
    			int indice2=0;
    			int freq_count[10000];
    			float freqsize=1000;
    			float bin_size=(maxval - minval)/freqsize;
    			for (passo=0; passo<freqsize; passo++)
    			{	
    				for (indice2 = 0; indice2 < i ; indice2++) 
    				{
    					if ((a[indice2]>minval+passo*bin_size)&(a[indice2]<minval+(passo+1)*bin_size)) 
    					{
    						freq_count[passo]++;
    						bin_center[passo]=minval+passo*bin_size;						
    					}
    					else if ((a[indice2]<minval+passo*bin_size))
    					{
    						bin_center[passo]=minval+passo*bin_size;			
    					}
    					else if ((a[indice2]>minval+(passo+1)*bin_size))
    					{
    						bin_center[passo]=minval+passo*bin_size;			
    					}
    				}
    			}
    			int ciao=0;
    			for (ciao=0; ciao<freqsize; ciao++)
    			{
    				printf("%f %f %i\n",step, (bin_center[ciao]*57.32-step), freq_count[ciao]);
    				FILE *destinazione;
    				destinazione = fopen("file.txt","a+"); /* apend file (add text to a file or create a file if it does not exist.*/
    				fprintf(destinazione,"%f %f %i\n",step, (bin_center[ciao]*57.32-step), freq_count[ciao]); /*writes*/
    				fclose(destinazione); /*done!*/				
    			}
    			memset(a, 0, i);
    			memset(freq_count, 0, i);
    			memset(bin_center, 0, i);
    			i=0;
    			step=step+0.01;
    			
    		}
    		/* conto il numero di elementi che mi interessa binnare */
    		else if ((limit2<max)&(limit2>min))
    		{	
    			a[i] = limit2;
    			i++;
    		}
    		/* fine del conteggio */			
    	}	
        fclose ( file );
        }
        else
        {
        perror ( filename ); /* why didn't the file open? */
        }
        return 0;
        }

  4. #4
    Registered User claudiu's Avatar
    Join Date
    Feb 2010
    Location
    London, United Kingdom
    Posts
    2,094
    You probably cannot allocate that much memory statically into line. Use malloc and realloc as necessary. It would also be useful to start a debugger like gdb and check how the variables change during run time.
    1. Get rid of gets(). Never ever ever use it again. Replace it with fgets() and use that instead.
    2. Get rid of void main and replace it with int main(void) and return 0 at the end of the function.
    3. Get rid of conio.h and other antiquated DOS crap headers.
    4. Don't cast the return value of malloc, even if you always always always make sure that stdlib.h is included.

  5. #5
    Registered User
    Join Date
    Jun 2011
    Posts
    5
    Quote Originally Posted by claudiu View Post
    You probably cannot allocate that much memory statically into line. Use malloc and realloc as necessary. It would also be useful to start a debugger like gdb and check how the variables change during run time.
    even changing

    Code:
    char line [8260000]
    to

    Code:
    char line [10]
    is not solving the problem.

    I'm very new to C programming. How to use gdb to check the code ??

    Thanks,
    Andrea

  6. #6
    Registered User
    Join Date
    Jun 2011
    Posts
    5
    Quote Originally Posted by claudiu View Post
    You probably cannot allocate that much memory statically into line. Use malloc and realloc as necessary. It would also be useful to start a debugger like gdb and check how the variables change during run time.
    ok,i've found a tutorial on the net and used gdv as the following

    from prompt i give the command

    gcc -g aa.c

    (aa.c is the name of my program)

    then i give the command

    gdb a.out

    A new prompt appears.

    I give the command "run" and the following error appears.

    Starting program: /home/andrea/Desktop/a.out

    Program received signal SIGSEGV, Segmentation fault.
    0xb7ec30a2 in fgets () from /lib/i386-linux-gnu/libc.so.6

    So, in my understanding the error is coming from fgets function. Is this right ?? If yes, how to solve it ??

    Best regards,
    Andrea

  7. #7
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229
    Type
    Code:
    bt
    to get a stack trace. See the parameters passed to fgets(). What are they? are they what you expect them to be?

  8. #8
    Registered User
    Join Date
    Jun 2011
    Posts
    5
    Quote Originally Posted by cyberfish View Post
    Type
    Code:
    bt
    to get a stack trace. See the parameters passed to fgets(). What are they? are they what you expect them to be?
    Typing bt gives

    #0 0xb7ec30a2 in fgets () from /lib/i386-linux-gnu/libc.so.6
    #1 0x08048b66 in main () at aa.c:20

    What does this means ?

    Thanks,
    Andrea

  9. #9
    Registered User
    Join Date
    May 2009
    Posts
    4,183
    You use the variable "i" without giving it a valid value.

    I suggest 1000 as a suitable value for line size.
    Code:
    char line [1000]; /* or other suitable maximum line size */
    Edit: I am not that good at using the debugger, so I can not help you with that.

    Tim S.
    Last edited by stahta01; 06-05-2011 at 04:37 PM.

  10. #10
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229
    Typing bt gives

    #0 0xb7ec30a2 in fgets () from /lib/i386-linux-gnu/libc.so.6
    #1 0x08048b66 in main () at aa.c:20

    What does this means ?

    Thanks,
    Andrea
    That means fgets is called from main, on line 20. In your case this may seem very obvious, it won't be the case in larger programs, when function calls can be a dozen levels deep.

    Then you can do
    Code:
    frame 1
    to go to the main() level.

    Then
    Code:
    print [variable name] on fget's parameters
    to see what they are.

  11. #11
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Quote Originally Posted by muppy View Post
    Typing bt gives

    #0 0xb7ec30a2 in fgets () from /lib/i386-linux-gnu/libc.so.6
    #1 0x08048b66 in main () at aa.c:20

    What does this means ?

    Thanks,
    Andrea
    That means that in your main function, on line 20 of file aa.c, you call fgets. fgets, like many standard library functions does not prevent you from shooting yourself in the foot. It has a set of pre-conditions you must satisfy to ensure the function wont crash. Most functions will crash on a null pointer, unless the documentation explicitly says it does something special with a null pointer. fgets is not broken, but you passed it some bad data.

    The #0, #1, etc are the stack frames, with 0 being the current one (where the program was when it died), and the numbers increasing as you "climb out" of your function calls, all the way up to main.

    Now, given Tim's observation that you're using i uninitialized, it makes this line look like the culprit:
    Code:
    memset(a, 0, i);
    memset(freq_count, 0, i);
    memset(bin_center, 0, i);
    ...
    a[i] = limit2;
    You set an unknown number of bytes starting at the beginning of the array a, freq_count and bin_center to zero. Or, depending on limit2, you set an arbitrary index in the array a to limit2. Since local, non-static variables reside on the stack and can have any value, you could very well be setting 93719892 bytes to zero, creating a massive buffer overflow and overwriting the your file handle, meaning fgets tries to read from a null file pointer, hence your seg fault (a seg fault means you're trying to read, write or execute memory you shouldn't). The problem with using an uninitialized stack variables is that it results in undefined behavior. It may always crash, or only sometimes crash, or it may never crash. It may give correct output, it may not. The problem may surface now, in 5 minutes or 5 years. You never know what will happen with undefined behavior. If you want to find out for sure, you can do the following in GDB:
    Code:
    $ gdb a.out
    
    (gdb) b main
    Breakpoint 1 at 0x80484e9: file file.c, line 7.
    (gdb) r
    Starting program: /home/cagarvin/sandbox/test/a.out
    
    Breakpoint 1, main () at file.c:7
    7           char filename[] = "bruco.coord";
    (gdb) n
    9           file= fopen (filename,"r");
    (gdb)
    10          if ( file != NULL )
    (gdb) n
    13              float step=-0.4;
    (gdb) n
    Using the n (next) command to step through your program line by line. At any given point, you can print the value of any variable in scope by typing 'p <variable name>'. Also, you can go to a specific frame number (the numbers preceeded by a # in your backtrace) by typing 'fr <number>'. Then you can examine the value of variables passed in. Those suspicious memset calls start on line 79, so you can set a second break point there with 'b 79', and type 'cont' to continue running the program. It should stop on line 79 so you can examine the contents of file ('p file'). Do likewise for the a[i] = ... line. Then move to the next line with 'n', and check file again. You'll probably see it get wiped at some point. Also, you should print i before you set it to zero, just to see what arbitrary value it may have.

    The debugger is probably your most valuable tool as a C programmer (except a good compiler I suppose), so learning to use it well is pretty much a necessity. We have a brief tutorial here, and Google can find much more for you.

    Also, there are a few other things you should do:
    1. Put some spaces around your operators and assignments (=, +, -, *, &&, etc), so your code is more readable. Readable code is key to finding problems.
    2. Use more descriptive variable names than a, so your code is readable.
    3. Use #defines or enums with sensible names instead of magic numbers. All the 100s, 1000s, 10000s, etc you use for array sizes make it hard to know what your intent is and whether you're doing something you shouldn't.
    4. Check the value of sscanf to make sure you successfully read and converted two values, otherwise you might be using the old value of limit2 and possibly even the old value of limit1 if you have a bad data file or some IO error.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. segmentation fault
    By petrovgovind in forum C Programming
    Replies: 5
    Last Post: 12-02-2010, 04:44 PM
  2. Segmentation fault
    By ankitsinghal_89 in forum C Programming
    Replies: 2
    Last Post: 06-28-2010, 01:45 AM
  3. Segmentation fault
    By phoneix_hallows in forum C Programming
    Replies: 8
    Last Post: 08-27-2009, 05:56 AM
  4. why it cause a Segmentation fault?
    By mycount in forum C Programming
    Replies: 1
    Last Post: 09-28-2006, 10:19 PM
  5. segmentation fault and memory fault
    By Unregistered in forum C Programming
    Replies: 12
    Last Post: 04-02-2002, 11:09 PM