簡體   English   中英

C取消引用指針中的分段錯誤

[英]Segmentation Fault in C dereferencing pointers

我試圖理解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其后更改的內存空間時,為什么取消引用會導致segFault 為什么不改為Paul 而且為什么它會首先引發段錯誤?

另外,我希望對箭頭-> vs *用於解引用指針的解釋有所理解。

這是不正確的,並且您應該收到警告:

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

meName是指向char的指針,而不僅僅是指向char的指針。 解決方法如下:

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

當然,打印應該看起來像這樣-即您注釋的方式:

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

首先,所有printfs使用%s代碼。 這意味着第二個參數將被解釋為指向表示字符的字節的指針(即地址)。 Printf將打印該字節的值(作為字符),然后打印內存中下一個字節的值,依此類推,直到遇到一個值為0的字節為止。

我將一次打印您的打印報表。

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

*meName表示位置meName處的字符。 該字符是-128到+127之間的整數。 (實際上是107 -參見下文。)現在,您正在使用107這個數字,就好像它是一個以null終止的字符串的地址(第一個字符)一樣。 可能是該數字不是有效地址,因此當printf嘗試讀取該地址處的字符(107)時,該字符不在進程的內存范圍內,因此您會遇到分段錯誤。 (通常,分段錯誤意味着您試圖在不允許訪問進程的地址上讀取或寫入內存。)

第二

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

更好是因為meName至少是一個指針。 那么它指向什么呢? 初始化

meName = &(head->name);

表示meName是字段head->name的地址( meName向該字段)。 請注意,這實際上不是字符,而是指向字符的指針。 因此,發生的情況是printf打印出head->name的第一個字節,就好像它是一個字符一樣。 它碰巧打印為k ,因此第一個字節為107( k的ascii編號)。 然后它打印指針的第二個字節,依此類推,直到碰巧有一個字節為00000000。為什么編譯器接受初始化對我來說仍然不清楚,因為左側的類型是“指向字符的指針”,並且右邊的類型是“指向字符的指針”。 它應該至少產生了一個警告錯誤。

第三版

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

這將查看地址head並找到一個結構。 所述的值name該結構的場是一個五個字節序列的第一個字節的地址'P' 'a' 'u' 'l' 0 printf遵循該指針值來查找'P' (其它打印),然后遞增指針,並再次跟隨指針以找到'a' ,依此類推,直到找到0字節,然后停止。

請注意,由於printf有點特殊,因此編譯器不會檢查其參數類型。 這就是為什么您的第一個printf編譯的原因,即使第二個參數的類型不是char*因為%s指令指示應該這樣做。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM