天天看点

【踩坑记录】【C/C++】数组名与指针的关系;数组名取地址;数组名的解引用与取地址;

文章目录

    • 前序知识
    • 指针与数组名的区别
      • 验证
      • 一维数组
      • 二维数组
    • 参考

前序知识

  1. 获取变量类型的语句是:

    typeid(variable).name()

  2. sizeof 是个关键字,在编译阶段起作用。
  3. sizeof 数组名,得到的是数组的字节大小。

指针与数组名的区别

  • C专家编程 中有讲到,
  • 数组和指针在编译器处理时是不同的,在运行时的表示形式也是不一样的,并可能产生不同的代码。对编译器而言,一个数组就是一个地址,而一个指针就是一个地址的地址。
  • 数组名是不可修改的左值,不能直接对其赋值(定义时除外)。但可以用memcpy,strcpy等来进行间接“赋值”。
  • 讲到三个规定
  1. “表达式中的数组名被编译器当作一个指向该数组第一个元素的指针。”
  2. "下标总是与指针的偏移量相同。
  3. “在函数参数的声明中,数组名被编译器当作指向该数组的第一个元素的指针。”(作为形参,数组名退化为指针)
  • 讲到三个例外
  1. 数组作为sizeof()的操作数,显然此时需要的是整个数组的大小,而不是所指向第一个元素的大小
  2. 使用&操作符取数组的地址
  3. 数组是一字符串常量初始化值

验证

int arr[3][3] = { 1,2,3,4,5,6,7,8,9 };
int arr2[3] = { 2,5,6 };
int(*p)[3] = &arr2;

cout << "(arr)		\t" << (arr) << " \t" << sizeof(arr) << "\t" << typeid(arr).name() << endl;
cout << "(arr + 1)  \t" << (arr + 1) << " \t" << sizeof(arr + 1) << "\t" << typeid(arr + 1).name() << endl;
cout << "(*arr)		\t" << (*arr) << " \t" << sizeof(*arr) << "\t" << typeid(*arr).name() << endl;
cout << "(*arr + 1)	\t" << (*arr + 1) << " \t" << sizeof(*arr + 1) << "\t" << typeid(*arr + 1).name() << endl;
cout << "(*(arr + 1))\t" << (*(arr + 1)) << " \t" << sizeof(*(arr + 1)) << "\t" << typeid(*(arr + 1)).name() << endl;
cout << "(&arr)		\t" << (&arr) << " \t" << sizeof(&arr) << "\t" << typeid(&arr).name() << endl;
cout << "(&arr+1)	\t" << (&arr + 1) << " \t" << sizeof(&arr + 1) << "\t" << typeid(&arr + 1).name() << endl;

cout << "*******************************************************************" << endl;

cout << "(arr2)		\t" << (arr2) << " \t" << sizeof(arr2) << "\t" << typeid(arr2).name() << endl;
cout << "(&arr2)	\t" << (&arr2) << " \t" << sizeof(&arr2) << "\t" << typeid(&arr2).name() << endl;
cout << "(arr2+1)	\t" << (arr2 + 1) << " \t" << sizeof(arr2 + 1) << "\t" << typeid(arr2 + 1).name() << endl;
cout << "(*arr2)	\t" << (*arr2) << " \t" << sizeof(*arr2) << "\t" << typeid(*arr2).name() << endl;
cout << "(*arr2+1)	\t" << (*arr2 + 1) << " \t" << sizeof(*arr2 + 1) << "\t" << typeid(*arr2 + 1).name() << endl;
cout << "((*arr2 )+1)\t" << ((*arr2) + 1) << " \t" << sizeof((*arr2) + 1) << "\t" << typeid((*arr2) + 1).name() << endl;
cout << "(p)	    \t" << (p) << " \t" << sizeof(p) << "\t" << typeid(p).name() << endl;
           
  • X86下结果
(arr)                   0117F834        36      int [3][3]
(arr + 1)       		0117F840        4       int (*)[3]
(*arr)                  0117F834        12      int [3]
(*arr + 1)              0117F838        4       int *
(*(arr + 1))    		0117F840        12      int [3]
(&arr)                  0117F834        4       int (*)[3][3]
(&arr+1)                0117F858        4       int (*)[3][3]
**********************************************
(arr2)                  0117F820        12      int [3]
(&arr2)         		0117F820        4       int (*)[3]
(arr2+1)                0117F824        4       int *
(*arr2)         		2       		4       int
(*arr2+1)               3       		4       int
((*arr2 )+1)    		3       		4       int
(p)             		0117F820        4       int (*)[3]
           

一维数组

  • int arr2[3] = { 1,2,3 };

name meaning type

(arr2)

数组名:指向第一行的指针(二维指针常量) int [3]

(&arr2)

一维数组的指针;(数组指针) int (*)[3]

(arr2+1)

数组指针+偏移;(指针) int *

(*arr2)

数组名解引用;(值) int

(*arr2+1)

数组名解引用+偏移;(值)(和下面一致;先解引用) int

((*arr2 )+1

数组名解引用+偏移;(值) int

二维数组

  • arr[i][j]

name meaning type

(arr)

数组名:指向第一行的指针;(二维指针常量)

int [3][3]

(arr + 1)

数组名+偏移;(指向一维数组的指针)

int (*)[3]

(*arr)

数组名解引用;(一维指针常量)

int [3]

(*arr + 1)

数组名解引用+偏移;(指针)

int *

(*(arr + 1))

数组名+偏移 +解引用;一维指针常量

int [3]

(&arr)

数组名取地址;(指向二维数组的指针)

int (*)[3][3]

(&arr+1)

数组名+偏移+取地址;(指向二维数组的指针)

int (*)[3][3]

  • tips:

若要快速得到一个二维数组最后一个元素的值可以这样

int *ptr = (*int)(&arr + 1);
cout << *(ptr - 1) << endl;
           
  • arr

    只是arr[0]的地址,arr+1就是arr[1]的地址了.
  • &arr

    是整个arr[10]的首地址,是以整个数组为角度来看,虽然它与arr[0]的值相同,但是&arr+1就已经增加了10个int类型的字节的长度了.
    【踩坑记录】【C/C++】数组名与指针的关系;数组名取地址;数组名的解引用与取地址;
  • 即,对数组名取地址,得到的是数组名所指元素的地址。和指针不同;(编译器特性)

参考

【C专家编程】

https://blog.csdn.net/hmxz2nn/article/details/80157461

继续阅读