指针和地址
指针存储变量在内存中的地址,比如c是一个字符串,那么p就是一个指针,存储c的内存地址,形象地理解p“指向”c

在对象名称前面加&,返回内存中对象的地址,适用于变量和数组,不适用于表达式、常量和register变量。
p = &c;
p现在就是一个指针,可以用*来表示。比如
int x = 1, y = 2, z[10];
int *ip; /* ip is a pointer to int */
ip = &x; /* ip now points to x */
y = *ip; /* y is now 1 */
*ip = 0; /* x is now 0 */
ip = &z[0]; /* ip now points to z[0] */
如果对*ip进行操作,那么被操作的就是它指向的对象。比如这里将x加1,
y = *ip + 1;
由于编译器是从右到左扫描的,所以如果对指针ip进行自增操作,++放在后面,需要用括号将指针括起来,否则就是ip自增。
++*ip
(*ip)++
函数也可以返回指针,类型加*。
char *alloc(int n) /* return pointer to n characters */
{
if (allocbuf + ALLOCSIZE - allocp >= n) { /* it fits*/
allocp += n;
return allocp - n; /* old p */
} else /* not enough room */
return 0;
}
指针之间可以进行减法,但不能进行加法运算,和其他类型可以进行任何形式的计算。
指针和参数
因为C语言是值传递,变量在传进函数后,无论函数对变量进行什么操作,都不会改变变量的值。比如这里进行交换操作就不行,最后x还是,y还是y。
void swap(int x, int y) /* WRONG */
{
int temp;
temp = x;
x = y;
y = temp;
}
如果要想改变x和y的值,就需要用到指针。
void swap(int *px, int *py) /* interchange *px and *py */
{
int temp;
temp = *px;
*px = *py;
*py = temp;
}
操作过程如下图

指针和数组
数组内特定索引的元素的内存地址也可以用指针存储,但要注意的是如果是*(指针+1)那么指向的是下一个元素的内存地址。
int a[10];
int *pa;
pa = &a[0];
*(pa+1) /*指向的是a[1]*/
如果是*(pa+2),那么就指向下下个数组的元素,即a[2]。如果是减1就是指向上一个。

如果不加*,那么就是对当前索引的元素进行操作。
pa+1; /*a[0]+1*/
像二分查找这样的算法,需要对指针进行操作,要么就需要用到减法,减的结果是索引之差,可以与另一个指针进行加法运算。
int *high = &tab[0];
int *low = &tab[10];;
mid = low + high;//非法
mid = low + (high-low) / 2
数组名称不是变量,而是数组的内存地址,即数组的第一个元素的内存地址。比如这里pa就相当于pa = &a[0],pa2就相当于pa = &a[2]。
pa = a;
pa2 = a+2;
不能对数组名称进行操作,比如a++;,这时非法的。
指针和二维数组
如果是存储二维数组的内存地址,那么需要一个数组。
char *name[] = { "Illegal month", "Jan", "Feb", "Mar" };
数组name的每个元素都是指向字符串的内存地址,而不是字符串本身。

如果是二维数组,就需要指定单个数组的长度,而不是给予
char aname[][15] = { "Illegal month", "Jan", "Feb", "Mar" };
main函数
main函数有两个参数来接受命令行传过来的数值,argc是命令行传过来的数值的个数,argv是传过来的字符串的指针数组。*argv[0]存储的是程序的内存地址,因此argc至少为1。
#include <stdio.h>
main(int argc, char *argv[])
{
int i;
for (i = 1; i < argc; i++)
printf("%s%s", argv[i], (i < argc-1) ? " " : "");
printf("\n");
return 0;
}

复杂声明
第一行代码是函数,返回的是指向int类型的指针。第二行代码是指针,指向返回int类型的函数。
int *f();
int (*pf)();
声明只是负责告诉编译器这个变量的存在,而不负责分配内存。在定义时,即给变量赋值时,才会分配内存。
C语言中,声明的形式为TypeName+Declarator。int iint是int是TypeName,是Declarator。“()”(非函数声明中的“()”)具有最高的紧密度,其次才是函数和数组的“()”和“[]”,即编译时先将“()”内的代码看成一个整体。
复杂声明的形式为
dcl: optional *'s direct-dcl
direct-dcl name
(dcl)
direct-dcl()
direct-dcl[optional size]
dcl是declaration的简写,一般就是带*的direct-dcl。direct-dcl是一个name,后面可以跟跟()或[optional size],也可以是(dcl)这种形式。
int (*pfa[])();中pfa是一个name,是direct-dcl。pfa[]就是direct-dcl[optional size]这种形式,也是一个direct-dcl。*pfa[]前面加上了*是一个dcl。(*pfa[])可以被看成一个direct-dcl,即(dcl)这种形式,int (*pfa[])();就可以看成是T D1()这种形式,是一个dcl

本文详细介绍了C语言中的指针概念,包括指针与地址的关系、指针与参数的交互、指针与数组的运用,特别是针对二维数组的指针操作。此外,还探讨了指针在函数参数传递中的重要作用,以及main函数中命令行参数的处理。文章最后讨论了复杂的声明方式,帮助读者理解C语言中指针和声明的复杂性。
1192

被折叠的 条评论
为什么被折叠?



