C解引用指针中的分段错误

时间:2014-09-27 15:52:23

标签: c arrays pointers malloc

我试图理解C编程中的指针和char数组。 我有一个名为player的结构定义如下:

typedef struct player{
    char* name;
    float ppm;
} player;

我在Main中有以下内容:

int main()
{
  player* head = (player*) malloc(sizeof(player));
  char* meName = &(head->name);
  (*head).name = "potato";
  (*head).name = "Paul";
  (*head).ppg =7.6;
  //printf("player is named %s\n", *meName); //First print
  printf("player is named %s\n", meName); //second print
  printf("player is named %s\n", (*head).name); //third print
  return 0;
}

为什么我的第一次打印会导致分段错误,为什么我的其他两个打印输出以下内容:

player is named k0@
player is named Paul

如果我没有弄错,meName应该指向一个内存地址,然后通过使用另一个指向同一内存地址的指针来更改。事实上,如果我在第二次打印中打印它,它会显示该地址。当我明确地将变量设置为指向之后被更改的内存空间时,为什么取消引用它会导致segFault?为什么不改为Paul?为什么它会首先抛出一个段错误?

另外,我很欣赏箭头的解释 - > vs *用于解除引用指针。

3 个答案:

答案 0 :(得分:3)

这是不正确的,你应该收到警告:

char* meName = &(head->name);

meName是指向char的指针,而不是指向char的指针。以下是解决问题的方法:

char** meName = &(head->name);

当然打印应该是这样的 - 即你已经注释掉的方式:

printf("player is named %s\n", *meName);

答案 1 :(得分:1)

首先关闭所有printfs使用%s代码。这意味着第二个参数将被解释为表示字符的字节的指针(即地址)。 Printf将打印该字节的值(作为字符),然后打印内存中下一个字节的值,依此类推,直到遇到值为0的字节为止。

我会一次一张你的打印报表。

printf("player is named %s\n", *meName);

*meName表示位置meName处的字符。该字符将是-128到+127之间的整数。 (实际上它是107 - 见下文。)现在你使用这个数字107,好像它是一个以空字符结尾的字符串的(第一个字符)的地址。有可能这个数字不是有效地址,因此当printf尝试读取该地址(107)处的字符时,它超出了进程的内存范围,因此您会遇到分段错误。 (通常分段错误意味着您尝试在不允许进程访问的地址上读取或写入内存。)

第二

printf("player is named %s\n", meName);

这更好,因为meName至少是一个指针。那是什么意思呢。初始化

meName = &(head->name);

表示meName是字段head->name的地址(即指向)。请注意,这实际上不是一个字符,而是一个指向字符的指针。那么会发生的是printf打印出head->name的第一个字节,好像它是一个字符。它碰巧打印为k,因此第一个字节为107(k的ascii编号)。然后它打印指针的第二个字节,依此类推,直到碰巧有一个字节为00000000.为什么你的编译器接受初始化我不清楚,因为左边的类型是“指向字符的指针”和右边的类型是“指向字符指针的指针”。它应该至少产生一个警告错误。

第三次印刷

printf("player is named %s\n", (*head).name);

这会查看地址head并找到一个结构。该结构的name字段的值是五字节序列'P' 'a' 'u' 'l' 0的第一个字节的地址。{{1跟踪此指针值以查找printf(它打印),然后它递增指针,再次跟随它以找到'P',依此类推,直到找到0字节并且那一点就停止了。

请注意,因为'a'有点特殊,所以编译器不会对其参数进行类型检查。这就是为什么第一个printf编译的原因,即使第二个参数的类型不是printf,因为%s指令表明它应该是。

答案 2 :(得分:0)

int main()
{
  player* head = (player*) malloc(sizeof(player));
  char* meName = &(head->name);
  (*head).name = "potato";
  (*head).name = "Paul";
  (*head).ppg =7.6;
  //printf("player is named %s\n", *meName); //First print
  printf("player is named %s\n", meName); //second print
  printf("player is named %s\n", (*head).name); //third print
  return 0;
}

此代码存在严重的类型错误(如果您使用了适当的警告级别,其中一些会被编译器捕获)并且不使用最佳实践(并且由于拼写错误而无法编译)。将其与

进行对比
int main(void)
{
  player* head = malloc(sizeof *head);
  char** pname = &head->name;

  head->name = "potato";
  head->name = "Paul";
  head->ppm = 7.6;

  printf("address of player name is %p\n", pname);
  printf("player is named %s\n", *pname);
  printf("ditto: %s\n", head->name);

  return 0;
}