4

Is the segmentation fault at the end of the code (just to allocate memory to 2D array and print the result)? The last printf statement is being printed and any code that I add at the end runs successfully and then segfault appears.

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int n,i,j,**mat;

    printf("\nEnter the size of the square matrix: ");
    scanf("%d",&n);

    *mat = (int **)malloc(n*sizeof(int *)); 

    for(i=0;i<n;i++)
    {
      mat[i]= (int *)malloc(n*sizeof(int));
    }

    for(i=0;i<n;i++)
    {
      for(j=0;j<n;j++) printf("%d\t",mat[i][j]=rand()%10*i+j);
      printf("\n\n\n");
    }

    printf("Bye\n");
    return 0;
}

Technically *mat in 8th line (printed in code) should be mat, but then everything is fine. The code mentioned compiles (with obvious warning of incompatible pointer type in gcc) and works except at the end when it prints segfault. Had there been a segfault in the program, it wouldn't had run till the end!

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
man_stack
  • 49
  • 1
  • 3
  • One possible explanation is that the return address from `main` has been overwritten on the stack, this is why it gives the segfault at the end of `main` function; probably because of wrong pointer usage. – m0skit0 Dec 14 '15 at 18:05
  • 6
    Since you apparently know that "`*mat` in 8th line (printed in code) should be `mat`", what exactly is your question? – John Bollinger Dec 14 '15 at 18:08
  • 2
    Your use of `*mat` invokes undefined behaviour. The variable `mat` is uninitialized; you dereference it. Anything can happen. The code is broken. In any case, you should have been using `mat = malloc(n * sizeof(*mat));` unless you're using a C++ compiler to compile C, in which case you need the cast in there. – Jonathan Leffler Dec 14 '15 at 18:08
  • Can you try this? Before the `*mat=` statement, add `printf("%p %p\n", &j, mat);`. Tell us the output. – Mark Plotnick Dec 14 '15 at 18:25
  • @MarkPlotnick While debugging, i tried to add printf statements to get the addresses and i was surprised to see that adding printf statement(not to print anything but &mat ) eliminated segfault. The printf("%p %p\n", &j, mat); doesn't make any change in output. Very confusing(i am new to C). – man_stack Dec 15 '15 at 08:29
  • @JonathanLeffler Can undefined behaviour successfully give same result consistently always. I just ran the code in infinite loop to check it. – man_stack Dec 15 '15 at 08:36
  • @JohnBollinger i am curious to know the reason of such behaviour. *mat can also act as a pointer (though incompatible) to array of pointers to n 1D arrays – man_stack Dec 15 '15 at 08:39
  • @man_stack, `*mat` designates a different object than does `mat` -- or it would do if `mat` held a valid pointer to allocated memory. It is `mat` that needs to be assigned a value at that point, and the assignment to `*mat` has no effect whatsoever on `mat`. Moreover, since at that point `mat` does not point to any object, the assignment to `*mat` produces undefined behavior, as JonathanLeffler already observed. That's where the explanation must end: the whole idea of undefined behavior is that C does not define what it is. – John Bollinger Dec 15 '15 at 16:47

3 Answers3

4
*mat = (int **)malloc(n*sizeof(int *));

should be

mat = (int **)malloc(n*sizeof(int *)); 

Unless I change the line to this, the program segfaults right there. Through sheer luck and undefined behaviour your program manages to run for a little longer.

Also there is no need to cast the return value of malloc. Here are a couple reasons why you probably shoudn't.

Community
  • 1
  • 1
Alexguitar
  • 722
  • 4
  • 15
  • 3
    He already know this: *"Technically *mat in 8th line(printed in code) should be mat"* – m0skit0 Dec 14 '15 at 18:07
  • 1
    Beat me too it >.< That mallocing error doesn't explain why his code still runs until the last `printf` statement, though. – Spencer D Dec 14 '15 at 18:08
  • 1
    @SpencerDoak: undefined behaviour means anything can happen, including things apparently working far better than you've any right to expect. That seems to be happening here. – Jonathan Leffler Dec 14 '15 at 18:10
  • O.K. even if i change the syntax as suggested except *mat, the program works showing that required memory was allocated. – man_stack Dec 15 '15 at 08:16
  • Such is the case with undefined behaviour. For your own sanity just focus on fixing and understanding errors, don't dig too deep into it, unless you're into software security. – Alexguitar Dec 15 '15 at 17:01
3

To actually answer your question, the reason you are getting a segmentation fault after the end of the main() function is because the stack has been corrupted.

The stack pointer has been overwritten, which means that when main() attempts to return, the stack pointer contains an invalid value. This causes your program to attempt to access memory from outside the process's address space. If you use exit(0) you may avoid the segmentation fault altogether.

Keep in mind that your program results in an undefined behavior. Sometimes you'll get a segmentation fault at the end, sometimes during execution, sometimes none at all (And all sorts of other weird things may happen).

Orestis P.
  • 805
  • 7
  • 27
  • While debugging, i tried to add printf statements to get the addresses and i was surprised to see that adding printf statement(not to print anything but &mat ) eliminated segfault. printf("%p \n",&mat); Also i ran the code no. of times in an infinite loop; it's consistent. – man_stack Dec 15 '15 at 08:43
  • Did you add the printf statements after the allocation of map in the loop? (Line 13 in main). – Orestis P. Dec 15 '15 at 13:40
  • P.2 just before *mat = malloc(n*sizeof(int *)); – man_stack Dec 15 '15 at 15:49
1

*mat = (int **)malloc(n*sizeof(int *)); is dereferencing an un-allocated pointer. This causes undefined behavior ...

Undefined means anything can happen. Have a read of this. It is certainly possible that you are not seeing the results of your bad de-allocation until the end of your program.

As a further note, you should not cast the result of malloc.So the following:

*mat = (int **)malloc(n*sizeof(int *));

needs to be replaced with:

mat = malloc(n * sizeof mat*);

Along with some modifications to the rest of your memory allocation lines.

Community
  • 1
  • 1
Fantastic Mr Fox
  • 32,495
  • 27
  • 95
  • 175