将 char[][] 转换为 char** 会导致段错误吗?

发布于 2024-09-02 21:16:36 字数 783 浏览 6 评论 0原文

好吧,我的 C 有点生疏了,但我想我应该用 C 来做我的下一个(小)项目,这样我就可以对其进行抛光,并且我已经有不到 20 行的段错误了。

这是我的完整代码:

#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;
}

我完全不知道这是如何导致段错误的。从 [][] 转换为 ** 时会发生什么!?这是我收到的唯一警告。

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]’

[][]** 真的不兼容指针类型吗?对我来说它们似乎只是语法。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

半岛未凉 2024-09-09 21:16:36

char[ROWS][COLS+1] 无法转换为 char**print_map 的输入参数应该是

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

or

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

不同之处在于 char** 意味着指向可以像这样取消引用的东西:

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

char(* )[n] 是指向连续内存区域的点,如下所示

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

如果将 (char(*)[5]) 视为 (char**)你得到垃圾:

   (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

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
私野 2024-09-09 21:16:36

当您执行此声明时:

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

您创建了一个字符数组的数组。字符数组只是一个字符块,而数组数组只是一个数组块 - 所以总的来说,main_map 只是一整堆字符。它看起来像这样:

| 'a' | '.' | 'b' | 'b' | 0 | 'a' | '.' | 'c' | '.' | 0 | ... | 'd' | 'c' | '.' | 0 |

当您将 main_map 传递给 print_map() 时,它会将 main_map 评估为指向数组第一个元素的指针 -所以这个指针指向该内存块的开头。您强制编译器将其转换为 char ** 类型。

当您在函数内计算 map[0] 时(例如,对于循环的第一次迭代),它会获取 map< 指向的 char * 值/代码>。不幸的是,正如您从 ASCII 艺术中看到的那样,map 指向 char * - 它指向一堆普通的char s。那里根本没有 char * 值。此时,您加载其中一些 char 值(4、或 8,或其他数字,具体取决于您平台上的 char * 有多大)并尝试解释这些作为 char * 值。

puts() 然后尝试遵循该伪造的 char * 值时,您会遇到分段错误。

When you do this declaration:

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

You create an array-of-arrays-of-char. An array-of-char is just a block of chars, and an array-of-arrays is just a block of arrays - so overall, main_map is just a whole heap of chars. It looks like this:

| 'a' | '.' | 'b' | 'b' | 0 | 'a' | '.' | 'c' | '.' | 0 | ... | 'd' | 'c' | '.' | 0 |

When you pass main_map to print_map(), it is evaluating main_map as a pointer to the first element of the array - so this pointer is pointing at the start of that block of memory. You force the compiler to convert this to type char **.

When you evaluate map[0] within the function (eg. for the first iteration of the loop), it fetches the char * value pointed to by map. Unfortunately, as you can see from the ASCII-art, map doesn't point to a char * - it points to a bunch of plain char s. There's no char * values there at all. At this point, you load some of those char values (4, or 8, or some other number depending on how big char * is on your platform) and try to interpret those as a char * value.

When puts() then tries to follow that bogus char * value, you get your segmentation fault.

烟若柳尘 2024-09-09 21:16:36

查看我的代码,我意识到列的数量是恒定的,但这实际上并不重要,因为它只是一个字符串。所以我改变了它,所以 main_map 是一个字符串数组(呃,字符指针)。这使得我可以只使用 ** 来传递它:

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

Looking at my code I realized that the amount of columns is constant, but it doesn't actually matter cause it's just a string. So I changed it so main_map is an array of strings(er, char pointers). This makes it so I can just use ** for passing it around also:

char *main_map[ROWS]={
  "a.bb",
  "a.c.",
  "adc.",
  ".dc."};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文