1. 程式人生 > 其它 >C/C++中指標與陣列的不同

C/C++中指標與陣列的不同

技術標籤:周部落格指標陣列反彙編c語言

疑問

首先通過下面例子丟擲疑問:

  • define.c
#include <stdio.h>

char g_str[] = "KunQAQrz";

void define_print(void) {
  printf("define_print() : %s\n", g_str);
}
  • main.c
#include <stdio.h>

extern char* g_str;

int main() {
  define_print();
  printf("main() : %s\n"
, g_str); return 0; }

對以上程式碼編譯執行:
程式結果
為什麼會發生段錯誤呢?下面將對錯誤進行分析。

原因分析

指標與陣列

指標:

  • 指標的本質是一個變數,它儲存的目標值是一個記憶體地址。
  • 指標運算與 * 操作符配合使用能夠模擬陣列的行為。

陣列:

  • 陣列是一段連續的記憶體空間
  • 陣列名可看做指向陣列第一個元素的常量指標。

指標與陣列在彙編層面的不同

#include <stdio.h>

int main() {
  int a[3] = {0};
  int* p = a;

  p[0] = 1;
  p[1] = 2;

  a[2] = 3;

  return 0
; }

編譯生成以上程式碼的可執行檔案,並用objdump反彙編生成彙編程式碼。
以下為部分彙編程式碼:

  p[0] = 1;    /* 省略了加上偏移量的操作 */
    117b:	48 8b 45 e0          	mov    -0x20(%rbp),%rax
    117f:	c7 00 01 00 00 00    	movl   $0x1,(%rax)
  p[1] = 2;
    1185:	48 8b 45 e0          	mov    -0x20(%rbp),%rax  /* 將指標p存的地址傳入暫存器中 */
    1189:	48 83 c0 04          	add    $0x4,%rax         /* 加上偏移量 */				  
    118d:	c7 00 02 00 00 00    	movl   $0x2,(%rax)       /* 將值賦值給暫存器所存地址的記憶體處 */	

  a[2] = 3;
    1193:	c7 45 f4 03 00 00 00 	movl   $0x3,-0xc(%rbp)   /* 直接將值賦值給對應記憶體處 */

通過上述彙編程式碼可得知,操作指標比運算元組多一個定址操作
指標與陣列的不同

解決疑問

通過原因分析瞭解到指標與陣列在彙編層面是不同的,而疑問中的例子,將define.c中的g_str[]陣列在main.c中當作指標來編譯。這樣得到的結果就是在main.c讀取g_str會多一次定址,從而訪問野地址的記憶體。
錯誤描述
所以在main.c想要正常列印g_str的內容,傳入g_str的地址即可:

  • main.c
#include <stdio.h>

extern char* g_str;

int main() {
  define_print();
  printf("main() : %s\n", &g_str);

  return 0;
}

結果:
在這裡插入圖片描述