英文出处:Dennis Kubes:  《Basics of Pointers and Arrays in C》。

关于C语言中指针和数组的争论就像是一场恶战。一方面,有些人觉得,所有人都必须承认指针与数组是不同的。而另一些人则认为数组被当成指针来处理,因此它们不应该有什么区别。这种现象让人迷惑。然而,这两种说法其实都是正确的。

数组不是指针,指针也不能说是数组。在C语言中,指针仅在内存中代表一个地址,而数组是许多连续的内存块,多个类型相似的元素存储在其中。更深入的解释,请参考我之前的博文《C语言内存地址》。在C语言的绝大多数情况下,数组被当作指针来处理,这也是使人困惑的地方。

数组表示法vs指针表示法

数组被当作指针来处理,具体指的下面两条:

  • 数组名变量代表了数组中第一个元素的地址。它并不是一个指针,但却表现得像一个不能被修改的常指针一样。
  • 程序在与数组交互的时候,用指针表示法代替数组表示法。

我们来看点代码吧。

// initialize an array of ints
int numbers[5] = {1,2,3,4,5};// standard array notation
int *ptr1 = numbers;
int val1 = numbers[0];// address of array notation
int *ptr2 = &numbers[0];
int val2 = *(&numbers[0]);// pointer + increment notation
int *ptr3 = numbers + 0;
int val3 = *(numbers + 0);// print out the address stored in the pointers
printf("*ptr1 = %p\n", (void *)ptr1);
printf("*ptr2 = %p\n", (void *)ptr2);
printf("*ptr3 = %p\n", (void *)ptr3);// print out the value at the pointer addresses
printf("val1 = %d\n", val1);
printf("val2 = %d\n", val1);
printf("val3 = %d\n", val1);

我们声明了一个包含5个int的数组,并将数组名变量numbers赋给了一个int指针,ptr1。numbers代表了这个数组第一个元素的地址,将其赋给ptr1正是把它当成了指针来使用。接着我们用数组表示法访问了第一个元素的值。

第二个例子中,我们用数组表示法取了数组中第一个元素的地址,之后我们用解引用第一个元素所在地址的方法访问了它。

第三个例子中,我们用指针运算将数组中第一个元素的地址赋值给ptr3,之后我们解引用相同的地址来得到它的值。

最后我们将所有存储在指针中的地址和所有在这些地址的int值输出到屏幕上。运行这段代码,你会得到类似下面的输出:

*ptr1 = 0x7fff6be1de60
*ptr2 = 0x7fff6be1de60
*ptr3 = 0x7fff6be1de60
val1 = 1
val2 = 1
val3 = 1

所有值都是相同的。接下来再看看下面的代码:

// initialize an array of ints
int numbers[5] = {1,2,3,4,5};
int i = 0;// print out elements using array notation
for (i = 0; i < 5; i++ ) {int value = numbers[i];printf("numbers[%d] = %d\n", i, value);
}// print out elements using pointer math + array indexing (yuck!)
for (i = 0; i < 5; i++ ) {int value = *(numbers + i);printf("*(numbers + %d) = %d\n", i, value);
}// print out elements using a single pointer
int *ptr = numbers;
for (i = 0; i < 5; i++ ) {int value = *ptr++;printf("%d, *ptr++ = %d\n", i, value);
}

运行它,你会得到以下输出:

numbers[0] = 1
numbers[1] = 2
numbers[2] = 3
numbers[3] = 4
numbers[4] = 5
*(numbers + 0) = 1
*(numbers + 1) = 2
*(numbers + 2) = 3
*(numbers + 3) = 4
*(numbers + 4) = 5
0, *ptr++ = 1
1, *ptr++ = 2
2, *ptr++ = 3
3, *ptr++ = 4
4, *ptr++ = 5

就像你看到的那样,所有过程得到了相同的结果。

数组表示法实际上就是指针运算。C语言标准只是将numbers[0]定义为*(numbers + 0)的语法糖。(译者注:语法糖,它意指那些没有给计算机语言添加新功能,而只是对人类来说更容易理解的语法。)无论何时,你写下一个数组表示法,比方说numbers[2],都会被编译器转换为*(numbers + 2)。这里,numbers表示数组中第一个元素的地址,+2则表示用于指针运算的偏移量。

数组变量

我们已经展示了,数组常被当作指针来处理,而且对于C编译器而言数组表示法就是指针运算。一些人自然而然地就做出了这样的假设:既然数组能被当成指针,指针也应该能赋值给数组。这是不对的,数组名变量不能被改变。我们看看下面的代码吧。

// initialize an array of ints
int numbers[5] = {1,2,3,4,5};
int numbers2[5] = {6,7,8,9,0};
int *ptr = numbers2;// this won't compile
numbers = numbers2;
numbers = &numbers2;
numbers = ptr;

这段代码不能通过编译。试一试,你会得到以下输出。

incompatible types when assigning to type ‘int[5]’ from type ‘int *’
incompatible types when assigning to type ‘int[5]’ from type ‘int (*)[5]’
incompatible types when assigning to type ‘int[5]’ from type ‘int *’

虽然数组名变量代表了数组第一个元素的地址,它却表现得像一个不能被更改的常指针一样。它不能接受一个别的数组名变量或是指向另一个数组的指针的赋值。思考一下,如果你有一个数组名变量A代表一个数组,而且你能够改变A的地址,那被A指向的内存将会发生生么?

接下来看看这段能够编译的代码。

// initialize an array of ints
int numbers[5] = {1,2,3,4,5};
int numbers2[5] = {6,7,8,9,0};
int *ptr1 = numbers;
int *ptr2 = numbers2;// this will compile
ptr1 = ptr2;// print the addresses
printf("numbers = %p\n", (void *)numbers);
printf("numbers2 = %p\n", (void *)numbers2);
printf("ptr1 = %p\n", (void *)ptr1);
printf("ptr2 = %p\n", (void *)ptr2);

它会输出这样的结果:

numbers = 0x7fff5ea3d230
numbers2 = 0x7fff5ea3d250
ptr1 = 0x7fff5ea3d250
ptr2 = 0x7fff5ea3d250

虽然不能直接改变数组名变量,我们仍然改变一个指向这个数组的指针。代码中,我们创建了两个数组,两个int指针。我们将numbers赋给了ptr1,将numbers2赋给了ptr2。接着我们将ptr2赋给了ptr1,最后输出结果。可以看到,ptr1和ptr2都指向了numbers2数组的第一个元素。

总结

我希望你们能够喜欢这篇对C语言中数组和指针的概述。我们没有囊括关于指针和数组的一切知识,但足以作为一个开始。跟往常一样,我非常愿意接受大家的评论和建议.

关于程序设计基石与实践更多讨论与交流,敬请关注本博客和新浪微博songzi_tea.

程序设计基石与实践之C语言指针和数组基础相关推荐

  1. 程序设计基石与实践系列之类型提升、内存分配,数组转指针、打桩和矢量变换

    英文出处:Peter Fačka: Guide to Advanced Programming in C C语言可用于系统编程.嵌入式系统中,同时也是其他应用程序可能的实现工具之一. 当你对计算机编程 ...

  2. 程序设计基石与实践系列之失落的C语言结构体封装艺术

    英文来源于 Eric S. Raymond-- The Lost Art of C Structure Packing 谁该阅读这篇文章 本文是关于削减C语言程序内存占用空间的一项技术--为了减小内存 ...

  3. 程序设计基石与实践系列之编写高效的C程序与C代码优化

    原文出处: codeproject:Writing Efficient C and C Code Optimization 虽然对于优化C代码有很多有效的指导方针,但是对于彻底地了解编译器和你工作的机 ...

  4. 程序设计基石与实践之实现数字七段显示与发扑克牌问题

    数字七段显示 问题描述: 我们经常看到的计算器上显示的数字,或电梯中显示的表示楼层的数字,实际上都是由7个发光器件组成的.如下所示.当不同器件被点亮时,可组合出不同的数字.你的任务是,对给定的一个整数 ...

  5. c语言指针数组 难点总结,C语言指针与数组的难点分析.pdf

    C语言指针与数组的难点分析,c语言指针数组,c语言二维数组指针,c语言指针数组初始化,c语言函数指针数组,c语言数组与指针,c语言结构体数组指针,c语言指向数组的指针,c语言字符串数组指针,c语言数组 ...

  6. c语言指针数组课件,C语言指针与数组教程课件.ppt

    C语言指针与数组教程;教学要求;本章主要内容;引子;#include void swap ( int x, int y ) { printf("调用时:x地址为:%p, 值为:%d\n&qu ...

  7. C语言 指针和数组区别 - C语言零基础入门教程

    目录 一.前言 二.指针和数组区别 1.通过 sizeof 获取大小 a.计算数组大小 b.计算指针大小 2.指针和数组赋值方式不同 a.指针赋值 b.数组赋值 3.指针是指针变量,数组是指针常量 三 ...

  8. c语言指针和数组的联系

    c语言指针与数组 **一.指针与一维数组** 1.一维数组的存储方式 2. 对一维数组名的理解 3. 数组下标和指针的关系 4.一位数组名与取数组首地址的区别 **二.指针与二维数组** 1.二维数组 ...

  9. C语言中指针与数组的区别,C语言 指针与数组的详解及区别

    C语言 指针与数组的详解及对比 通俗理解数组指针和指针数组 数组指针: eg:int( *arr)[10]; 数组指针通俗理解就是这个数组作为指针,指向某一个变量. 指针数组: eg:int*arr[ ...

最新文章

  1. javascript primise本质——为了简化异步编码而针对异步操作的代理
  2. pytorch线性模型的基础使用
  3. springboot启动后进页面出现错误(java.sql.SQLNonTransientConnectionException: CLIENT_PLUGIN_AUTH is required)
  4. html5离线保存需要联网吗,html5 离线存储
  5. python随机出100道加法题_自动出题随机100题-20以内加减法全部算式
  6. could not stop cortex-m device 问题
  7. C++11新特性之auto关键字的使用
  8. Windows域控设置客户端禁用运行/cmd命令行【全域策略生效】
  9. 程序员面试金典——5.7找出缺失的整数
  10. Python2.x(3.x)安装及Ulipad的安装和使用
  11. Excel和Python求解线性规划问题
  12. 屏幕共享技术及相关软件使用测评
  13. MS08067利用方法
  14. ​杭州,苏州,成都哪个最宜居?
  15. android电视,手机控制,Android手机遥控电视:智能语音控制节目
  16. HDU 5698 瞬间移动 (组合数 + 阶乘逆元)
  17. 'CALayer position contains NaN: [nan nan]'异常
  18. Redis 基础 - 优惠券秒杀《非集群》
  19. 网络划分与寻址三要素: IP地址、子网掩码和地址分类
  20. 数量技术宅·安徽财经大学 线上策略分享会

热门文章

  1. 听说厕所要革命???智慧厕所|智慧公厕|智慧城市
  2. Django中urls路由转发和路由的path方法
  3. Window快捷键大全好玩的高手体验--欢迎评论区补充
  4. 大整数乘法(Comba 乘法 (Comba  Multiplication)原理)
  5. 1213: 不吉利的数字
  6. 计算机的硬盘有几个区,电脑硬盘应该分几个区比较合适?
  7. 关于GNSS接收机的整体设计概述
  8. 日常计算机网络英语对话,社交网络用语的英文表达进入了我们的日常对话
  9. 双十一买哪款蓝牙耳机划算?性价比高的蓝牙耳机排行榜
  10. c语言常用编程,常用C语言编程的习惯.doc