C/C++中指標與陣列的不同
阿新 • • 發佈:2021-01-05
疑問
首先通過下面例子丟擲疑問:
- 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;
}
結果: