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

结果:


image
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容