原文
http://blog.csdn.net/sdspp/archive/2006/02/27/611611.aspx
指针是c语言的精髓,理解它对于学习c语言至关重要。
1.指针和地址
指针是能够存放一个地址的一组存储单元。是一种保存变量地址的变量。
如 int x=1,y=2,z[10];
int *ip; /* ip是指向int类型的指针 */
ip = &x; /* ip 指向 x */
y = *ip; /* y 的值现在是1 */
*ip = 0; /* x的值现在是0*/
ip = &z[0]; /* ip指向z[0] */
其中一元运算符&可用于取一个对象的地址。地质运算符&只能应用于内存中的对象,即变量和数组元素。他不能作用于表达式,常量或register类型的变量。
一元运算符* 是间接寻址或间接引用运算符。当他作用于指针时,将访问指针所指向的对象。
y = *ip + 1;
*ip += 1;
++*ip;
(*ip)++;
这几条语句是等价的。其中(*ip)++中的括号是必需的。如果是*ip++,该表达式将是对ip进行加一运算,而不是对ip指向的对象进行加一运算。这是因为,类似于*和++这样的一元运算符遵循从右制左的结合顺序。
理解这点非常重要,它可以帮我们写出很简洁的程序。
void strcpy(char *s, char *t)
{
while(*s++ = *t++)
;
}
再如:
int strcmp(char *s, char *t)
{
while(*s++ == *t++)
if(*s =='\0')
return 0;
return *s-*t;
}
再如:
*p++ = val; /* 将val压入栈 */
val = *--p /* 将栈顶元素弹出到val中 */
这里涉及到一个问题,就是优先级的问题。*,++,--,具有相同的优先级,按照从右到左的顺序结合。按照这个原则上叙的就不难理解。究竟是对地址改变,还是对地址所引用的值变换。
再如,命令行操作经常遇到的:argv[0]保存命令好的第一个单词,通常是命令。(*argv)[0]同*argv[0]就完全不一样。因为[ ]的优先级要比*的高,所以(*++argv)[0]可以看作是**++argv,是命令的第一个字母。而*++argv[0]就相当于增加argv[0]指针。可以借此来遍历命令行之后的参数的内容。
2.指针和数组
在c语言中,指针和数组的关系十分密切。通过数组下标能完成的任何操作都可以通过指针来实现。一般来说,用指针写的程序比用数组下标写的程序执行速度快一些,但另一方面,用指针实现的程序理解起来稍微困难一些。
int a[10];
int *pa;
pa = &a[0]; /* 指针pa指向数组a的第0个元素,也就是说,pa的值为数组a[0]的地址。*/
因为数组名所代表的就是该数组最开始的一个元素的地址。
所以 pa=&a[0];等价于:pa = a;
a[i] 等价于:*(a+i); /* a[i]在c语言内部表示为*(a+i) */
&a[i] 等价于:a+i;
pa[i] 等价于:pa+i;
但是,我们必须记住,数组名和指针之间有一个不同之处。指针是一个变量,因此,在c语言中,语句pa=a和pa++都是合法的。但数组名不是变量,因此,类似于a=pa和a++形式的语句是非法的。
3.地址运算
有效的指针运算包括相同类型指针之间(也可以是两个指针之一是void*类型的情况)的赋值运算;指针同整数之间的加法或减法运算;指向相同数组中元素的两个指针间的减法或比较运算;将指针赋值为0或者指针与0之间的比较运算。其他所有形式的指针运算都是非法的。
4.字符指针
字符串常量是一个字符数组。在字符串的内部表示中,字符数组以空字符'\0'结尾。所以,程序可以通过检查空字符找到字符数组的结尾。
下面这两个定义有很大差别:
char amessage[] = "now is the time"; /* 定义一个数组 */
char *pmessage = "now is the time"; /* 定义一个指针 */
amessage是一个仅仅足以存放初始化字符串以及空字符'\0'的一维数组。数组中的单个字符可以进行修改,但amessage始终指向同一个存储位置。另一方面,pmessage 是一个指针,其初值指向一个字符串常量,之后他可以被修改为指向其他地址,但如果试图修改字符串的内容,结果是没有定义的。
5. 指针数组
其实也不能理解。
char *lineptr[MAXLINE];
他表示lineptr是一个具有MAXLINE个元素的一维数组,其中数组的每个元素是一个指向字符类型对象的指针。也就是说,lineptr[i]是一个字符指针,而*lineptr[i]是该指针指向的第i个文本行的首字符。
所以lineptr本身就是一个数组名,只不过它保存的是一些指针。存储的内容不同而已。
再如:
int a[10][20];
int *b[10];
对a来说,是分配了200个int型的空间。
而对b来说,该定义仅仅分配了10个指针,并且没有初始化他们。他们的初始化必须显式进行。
其中[]的优先级高于*的优先级。
所以,int *b[10]; 同int (*b)[10];是完全不一样的。
对于int *b[10]; b是一个数组名,数组内有10个整型指针。
对于int (*b)[10],意味着b是一个指针,他指向具有10个整型元素的一维数组。
int b[2][10]; int b[][10]; int (*b)[10] ;等价的。
一般来说,除数组的第一维(下标)可以不指定大小,其余各维都必须明确指定大小。
分享到:
相关推荐
python学习资源
jfinal-undertow 用于开发、部署由 jfinal 开发的 web 项目
基于Andorid的音乐播放器项目设计(国外开源)实现源码,主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的学习者,也可作为课程设计、期末大作业。
python学习资源
python学习资源
python学习一些项目和资源
【毕业设计】java-springboot+vue家具销售平台实现源码(完整前后端+mysql+说明文档+LunW).zip
HTML+CSS+JavaScarip开发的前端网页源代码
python学习资源
【毕业设计】java-springboot-vue健身房信息管理系统源码(完整前后端+mysql+说明文档+LunW).zip
成绩管理系统C/Go。大学生期末小作业,指针实现,C语言版本(ANSI C)和Go语言版本
1_基于大数据的智能菜品个性化推荐与点餐系统的设计与实现.docx
【毕业设计】java-springboot-vue交流互动平台实现源码(完整前后端+mysql+说明文档+LunW).zip
内容概要:本文主要探讨了在高并发情况下如何设计并优化火车票秒杀系统,确保系统的高性能与稳定性。通过对比分析三种库存管理模式(下单减库存、支付减库存、预扣库存),强调了预扣库存结合本地缓存及远程Redis统一库存的优势,同时介绍了如何利用Nginx的加权轮询策略、MQ消息队列异步处理等方式降低系统压力,保障交易完整性和数据一致性,防止超卖现象。 适用人群:具有一定互联网应用开发经验的研发人员和技术管理人员。 使用场景及目标:适用于电商、票务等行业需要处理大量瞬时并发请求的业务场景。其目标在于通过合理的架构规划,实现在高峰期保持平台的稳定运行,保证用户体验的同时最大化销售额。 其他说明:文中提及的技术细节如Epoll I/O多路复用模型以及分布式系统中的容错措施等内容,对于深入理解大规模并发系统的构建有着重要指导意义。
基于 OpenCV 和 PyTorch 的深度车牌识别
【毕业设计-java】springboot-vue教学资料管理系统实现源码(完整前后端+mysql+说明文档+LunW).zip
此数据集包含有关出租车行程的详细信息,包括乘客人数、行程距离、付款类型、车费金额和行程时长。它可用于各种数据分析和机器学习应用程序,例如票价预测和乘车模式分析。
把代码放到Word中,通过开发工具——Visual Basic——插入模块,粘贴在里在,把在硅基流动中申请的API放到VBA代码中。在Word中,选择一个问题,运行这个DeepSeekV3的宏就可以实现在线问答
【毕业设计】java-springboot+vue机动车号牌管理系统实现源码(完整前后端+mysql+说明文档+LunW).zip
【毕业设计】java-springboot-vue交通管理在线服务系统的开发源码(完整前后端+mysql+说明文档+LunW).zip