Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

casting char[][] to char** causes segfault?

Ok my C is a bit rusty but I figured I'd make my next(small) project in C so I could polish back up on it and less than 20 lines in I already have a seg fault.

This is my complete code:

#define ROWS 4
#define COLS 4

char main_map[ROWS][COLS+1]={
  "a.bb",
  "a.c.",
  "adc.",
  ".dc."};

 void print_map(char** map){
  int i;
  for(i=0;i<ROWS;i++){
    puts(map[i]); //segfault here
  }
 }



int main(){
  print_map(main_map); //if I comment out this line it will work.
  puts(main_map[3]);
  return 0;
}

I am completely confused as to how this is causing a segfault. What is happening when casting from [][] to **!? That is the only warning I get.

rushhour.c:23:3: warning: passing argument 1 of ‘print_map’ from incompatible pointer type
rushhour.c:13:7: note: expected ‘char **’ but argument is of type ‘char (*)[5]’

Are [][] and ** really not compatible pointer types? They seem like they are just syntax to me.

like image 677
Earlz Avatar asked May 24 '10 07:05

Earlz


People also ask

What causes a segfault?

A segfault occurs when a reference to a variable falls outside the segment where that variable resides, or when a write is attempted to a location that is in a read-only segment.

What happens segfault?

A segmentation fault occurs when a program attempts to access a memory location that it is not allowed to access, or attempts to access a memory location in a way that is not allowed (for example, attempting to write to a read-only location, or to overwrite part of the operating system).

Can malloc cause segfault?

It is usually the next-block pointer inside the malloc that is changed by your heap corruption to an invalid address, so that when you call malloc an invalid pointer gets dereferenced and you get a segmentation fault.

What causes segmentation fault with pointers?

A segmentation fault usually occurs when you try to access data via pointers for which no memory has been allocated. It is thus good practice to initialize pointers with the value NULL, and set it back to NULL after the memory has been released.


1 Answers

A char[ROWS][COLS+1] cannot be cast into a char**. The input argument of print_map should be

void print_map(char map[][COLS+1])

or

void print_map(char (*map)[COLS+1])

The difference being that a char** means to point to something that can be dereferenced like this:

   (char**)map
       |
       v
  +--------+--------+------+--------+-- ...
  | 0x1200 | 0x1238 | NULL | 0x1200 |
  +----|---+----|---+--|---+----|---+-- ...
       v        |      =        |
    +-------+   |               |
    | "foo" | <-----------------'
    +-------+   |
                v
             +---------------+
             | "hello world" |
             +---------------+

While a char(*)[n] is a points to a continuous memory region like this

   (char(*)[5])map
       |
       v
  +-----------+---------+---------+-------------+-- ...
  | "foo\0\0" | "hello" | " worl" | "d\0\0\0\0" |
  +-----------+---------+---------+-------------+-- ...

If you treat a (char(*)[5]) as a (char**) you get garbage:

   (char**)map
       |
       v
  +-----------+---------+---------+-------------+-- ...
  | "foo\0\0" | "hello" | " worl" | "d\0\0\0\0" |
  +-----------+---------+---------+-------------+-- ...
      force cast (char[5]) into (char*):
  +----------+------------+------------+------------+-- ...
  | 0x6f6f66 | 0x6c686500 | 0x77206f6c | 0x646c726f |
  +----|-----+---------|--+------|-----+------|-----+-- ...
       v               |         |            |
    +---------------+  |         |            v
    | "hsd®yœâñ~22" |  |         |       launch a missile
    +---------------+  |         |
                       v         v
               none of your process memory
                        SEGFAULT
like image 169
kennytm Avatar answered Sep 22 '22 23:09

kennytm