一般情况下,C语言中数组名在表达式中被解读为指向数组首元素的指针

C语言中数组名在表达式中被解读为指向数组首元素的指针, 即数组名在表达式中值为数组首元素的地址。(但有个例外,int a[2];int (*pa)[2]; pa=&a;数组名前加&,取得“指向数组的指针”,这时a不解读为指向数组首元素的地址)。根据ANSI C的定义,在数组前加上&,可以取得“指向数组的指针”。
例如,int a[2];在表达式中a表示数组首元素地址;
再例如,int a[3][2];在表达式中a仍然表示数组首元素的地址,不过此时数组a的基本元素是int[2],因此a+1每次会增加基本元素int[2]的大小。

C语言中不存在多维数组,只存在数组的数组,所谓的多维数组是便于理解提出的一种说法而已。
C语言中数组类型是包含元素个数的。

示例1:

#include <stdio.h>int main()
{int a[3][2] = { 0 };for (int i = 0; i != 3; ++i){for (int j = 0; j != 2; ++j){printf("a[%d][%d]: %p\t",i,j,&a[i][j]);}printf("\n");}printf("\n");printf("&a + 1: %p\n", &a + 1); // 实际相对于a[0][0]地址增加了3*2*sizeof(int)=24printf("a + 1: %p\n", a + 1);   // 实际相对于a[0][0]地址增加了2*sizeof(int)=8printf("\n--------------------------------------------\n\n");int b[3] = { 0 };printf("&b[0]: %p\n", &b[0]);   // 数组b首元素地址printf("&b + 1: %p\n", &b + 1); // 实际相对于b[0]地址增加了3*sizeof(int)=12printf("b + 1: %p\n", b + 1);   // 实际相对于b[0]地址增加了sizeof(int)=4return 0;
}

输出的结果可能是:

图1 结果示意

示例2:

#include <stdio.h>int main() {int arr[5] = { 1,2,3,4,5 };int(*parr)[5];parr = &arr;  // parr只有一个元素,即arrfor (int i = 0; i != 5; ++i){// (*(parr+0))[i] += 1;// (*parr)[i] += 1;parr[0][i] += 1;  // 很容易错写成parr[i] += 1;}for (int i = 0; i != 5; ++i){// printf("%d\n", (*parr)[i]);printf("%d\n", parr[0][i]);  // 输出结果为2 3 4 5 6}
}

C语言指针和数组同阶

所谓阶是方便理解自己发明的名词。
指针和数组同阶是指使用数组名的地方可以直接替换为指针。
如果数组作为指针(所指向的数组)的一个元素,则指针是数组的高阶。此时,称指针是高阶指针,数组是低阶数组。【注意不同颜色数组的含义】【此时指针是数组指针】
(不讨论其它诸如低阶指针、高阶数组的情况)。

题外话,C语言中用英语的规则阅读复杂数据类型便于理解。
例如,int a[3];表示a是数组,该数组的元素是int类型。 用英语阅读则是:a is array of int。
再例如,int a[3][2];表示a是数组(元素个数2,元素类型int)的数组(元素个数3,元素类型int[2]),数组a的元素还是数组(int [2])。因此在表达式中a仍然表示指向数组首元素(类型是int[2])的地址,类型为int(*)[2]。 用英语阅读则是:a is array(元素个数3,元素类型int[2]) of array(元素个数2,元素类型int)。

指针和数组同阶示例1:

#include <stdio.h>/* num表示数组指针p指向的数组包含的元素个数,类比成所谓的多维数组的行数 */
void triple(int (*p)[2], int num)
{for (int i = 0; i != num; ++i){for (int j = 0; j != 2; ++j){p[i][j] *= 3;}}
}int main()
{/* C语言不存在多维数组.数组a有三个元素每个元素是int[2]类型 */int a[3][2] = { {1,2},{3, 4},{ 5,6 }};for (int i = 0; i != 3; ++i){for (int j = 0; j != 2; ++j){printf("%d\t", a[i][j]);}printf("\n");}printf("---------------\n");/* 在表达式中数组名表示数组首元素的地址,a的元素类型是int[2],指向int[2]类型的指针的类型是int(*)[2],即在表达式中a表示函数triple()第一个参数的类型 */triple(a, 3);  // 数组a与triple()的第一个参数p是同阶的,同阶指针赋值法是将数组名直接赋值给指针for (int i = 0; i != 3; ++i){for (int j = 0; j != 2; ++j){printf("%d\t", a[i][j]);}printf("\n");}return 0;
}

输出结果:

图2 结果示意

指针和数组同阶示例2:

#include <stdio.h>int main() {int arr[5] = { 1,2,3,4,5 }; // 低阶数组int(*parr)[5];              // 高阶指针parr = &arr;                // 高阶指针赋值法,将低阶数组的地址赋给高阶指针for (int i = 0; i != 5; ++i){// (*(parr+0))[i] += 1;// (*parr)[i] += 1;parr[0][i] += 1;  // 很容易错写成parr[i] += 1;}for (int i = 0; i != 5; ++i){// printf("%d\n", (*parr)[i]);printf("%d\n", parr[0][i]);  // 输出2 3 4 5 6}return 0;
}

指针和数组同阶示例3:

#include <stdio.h>int main() {int arr[5] = { 1,2,3,4,5 };  // arr是parr的同阶数组int *parr;                   // parr是arr的同阶指针parr = arr;                  // parr与arr是同阶的.同阶指针赋值法,将数组名直接赋给指针for (int i = 0; i != 5; ++i){parr[i] += 1;}for (int i = 0; i != 5; ++i){printf("%d\n", parr[i]);  // 输出2 3 4 5 6}return 0;
}

指针和数组同阶示例4:

#include <stdio.h>int main()
{int b[4] = { 0,1,2,3 };int c[4] = { 4,5,6,7 };int(*p)[4] = malloc(sizeof(int)*4*2);for (int j = 0; j < 2; ++j){for (int i = 0; i < 4; ++i){if (j == 0){p[j][i] = b[i];}if (j == 1){p[j][i] = c[i];}}}for (int i = 0; i < 2; ++i){printf("%d %d %d %d \n", p[i][0], p[i][1], p[i][2], p[i][3]); // 输出:0 1 2 3 }// 输出:// 0 1 2 3 // 4 5 6 7 free(p);return 0;
}

传参示例:

#include <iostream>
#include <typeinfo>
/*编译环境:cmake -G "Visual Studio 15 2017" -A x64 ..
*/
namespace test_hybrid
{void testPointArray(){int a[2][3] = {-1,-2,-3,1,2,3};int (*p)[3] = a; // p是数组指针,每加1步进a的一个元素个大小,即3*sizeof(int);(注意多维数组是数组的数组,即a的每个元素是int[3])for(int i = 0; i < 3; ++i){// 可能的输出p[0] = 00000000001BF7C8, p[1] = 00000000001BF7D4, p[2] = 00000000001BF7E0,std::cout << "p[" << i << "] = " << p[i] << ", ";}std::cout << std::endl;// p = a[1];  // error C2440: “=”: 无法从“int [3]”转换为“int (*)[3]”p = &a[1];for(int i = 0; i < 3; ++i){std::cout << "(*p)[" << i << "] = " << (*p)[i] << ", ";}std::cout << std::endl;      }void testFunc1(int(*p)[3], int size){std::cout << "&p is: " << &p << std::endl;   // 可能的输出: 0133F86C,与&a不同std::cout << "&(p[0]) is: " << &(p[0]) << std::endl; // 可能的输出: 0133F880,与&a相同for(int i = 0; i < size; ++i){for(auto it: p[i]){std::cout << it << ", ";}}std::cout << std::endl;}void testFunc2(int **p){std::cout << "Entering testFunc2()...\n";}auto main() -> void {std::cout << "testing hybrid..." << std::endl;testPointArray();int a[2][3] = {-1,-2,-3,1,2,3};std::cout << "&a is: " << &a << std::endl;  // 可能的输出: 0133F880testFunc1(a, sizeof(a) / sizeof(a[0]));// testFunc2(a); // [ERROR]error: cannot convert 'int (*)[3]' to 'int**'auto b = a;std::cout << "type(b): " << typeid(b).name() << std::endl;  // int (* __ptr64)[3]int a2[] = {1,2,3,4};auto c = a2;std::cout << "type(c): " << typeid(c).name() << std::endl;  // int * __ptr64auto &d = a2;std::cout << "type(d): " << typeid(d).name() << std::endl;  // int [4]}
}

输出:

testing hybrid...
p[0] = 000000F287F9F978, p[1] = 000000F287F9F984, p[2] = 000000F287F9F990,
(*p)[0] = 1, (*p)[1] = 2, (*p)[2] = 3,
&a is: 000000F287F9FA08
&p is: 000000F287F9F9E0
&(p[0]) is: 000000F287F9FA08
-1, -2, -3, 1, 2, 3,
type(b): int (* __ptr64)[3]
type(c): int * __ptr64
type(d): int [4]

C语言中数组名到底是什么?相关推荐

  1. 从编译器角度分析C语言中数组名和指针的区别

    从编译器角度分析C语言中数组名和指针的区别 数组名和指针是两个往往很容易让人们混淆的概念,很多人以为数组名就是一个指针,也有很多人知道数组名不同于指针但是仅知道数组名的值不能像指针一样改变. 例如你可 ...

  2. C语言中数组名和指针的区别

    1: 指针是一个变量,而数组名不是.数组名是数组的首地址,即它本身就是一个地址. 2:假设a是一个数组名,而p是一个指针,当你使用 a 和 &a 时,得到值是一样的,都是数组的起始地址.而使用 ...

  3. c语言中数组名a和a详细介绍

    其实这两个东西挺难理解的,应该也没有那么重要,了解一下好了,主要还是要多多理解数组指针的运算 最近又把学习c语言提上日程上来了~~~先把我打算看的书都写下来吧,<C语言深度剖析>,< ...

  4. c语言中数组名可以与其他变量名相同,C语言初学者入门讲座 第九讲 数组(1)...

    C语言初学者入门讲座 第九讲 数组(1) (2007-01-17 11:39:19) 数组在程序设计中,为了处理方便,把具有相同类型的若干变量按有序的形式组织起来.这些按序排列的同类数据元素的集合称为 ...

  5. 关于对C语言中数组名取地址加减等操作的一点探究

    对于数组名取地址强制转换的操作 偶然在晚上学了C语言指针后网页闲逛找题时,被一个数组名取地址搞糊涂了,在自己试验加探索后我稍微悟了一点东西. 代码如下: #include<stdio.h> ...

  6. c语言中数组名和数组名取地址理解

    1.数组名是个指针型常量,也就是值不能被改变.(指针常量和常量指针区别见本文) char *str = "hello"; char  ch[6] = "hello&quo ...

  7. 图解C语言中数组指针、指针数组、函数指针、函数指针数组、指向函数指针数组的指针

    关于C语言中数组指针.函数指针.指针数组.函数指针数组.指向函数指针数组的指针一直比较绕,稍微整理一下. 到底是指针还是数组? 其实到底是指针还是数组还是看变量名与[]先结合还是*先结合.我们知道C语 ...

  8. python到底是啥_Python语言中的__init__到底是干什么的?

    本文主要向大家介绍了Python语言中的__init__到底是干什么的?通过具体的内容向大家展示,希望对大家学习Python语言有所帮助. 看到Python中有个函数名比较奇特,__init__我知道 ...

  9. c语言中数组的变量j是什么,c语言中数组,一般数组

    c语言中数组,一般数组. 1.什么是数组,数组有什么用? 为了方便处理而把类型相同的变量有序地组织起来的一种形式. 类型相同的元素集中起来,在内存上排成一条直线. 2.数组的声明. 元素类型.变量名和 ...

最新文章

  1. OpenGL之正背面剔除、深度测试与多边形偏移
  2. 了解一下HTTP1.1 Pipelining技术
  3. post请求改成body_post请求body格式
  4. Qt Installer Framework翻译(5-2)
  5. 运营商利润不均衡(转)
  6. 【Oracle】ORA-01157: cannot identify/lock data file 201 - see DBWR trace file
  7. 技术分享 — Java如何实现证件照换底色
  8. 普歌-码上鸿鹄团队-复习系统模块
  9. 道友自诉:入职中软一个月(外包华为)就离职了!
  10. CAD设置超链接(网页版)
  11. BI工具数据看板哪个好,瓴羊Quick BI整不错!
  12. 云开发实现小程序获取服务器时间并显示 如:淘宝下单时间
  13. Html+CSS 文本的强制换行
  14. Resnet18-cifar10及Million-AID数据加载
  15. 计算机主机配置科普,一秒看懂电脑配置,组装电脑不求人
  16. 100个网络基础知识
  17. 医学影像组学人工智能应用实践
  18. 怎么样才能锻炼好口才
  19. 爱奇途——追求技术,提升自我
  20. 唱作俱佳 腾讯AI艾灵领唱中国新儿歌

热门文章

  1. 一周热图|孙燕姿演绎全新TVC;谢霆锋助阵特步;苗苗成为自然堂女士护肤代言人...
  2. RGB 颜色空间肤色检测
  3. android 无线充电手机型号,支持无线充电的手机有哪些?5款支持无线充电的手机推荐 (2)...
  4. 学习Java day08 面向对象
  5. 用matlab调用笔记本摄像头拍照程序
  6. Java 替换字符串中空格的三种方法
  7. 编写脚本批量 ping
  8. sunwebscan下载_sunscanner.dll,下载,简介,描述,修复,等相关问题一站搞定_DLL之家
  9. 用计算机讲话小品,搞笑小品剧本《计算器》台词完整版 张京赵晨乐.docx
  10. Altium Designer如何打开PROTEL 99SE DDB文件