##指针与地址 p = &c把c的地址赋值给p,我们称p为指向c的指针。地址运算符只能作用于内存中的对象,即变量和数组元素。即这样是合理的p = &c[0].
一元运算符*是间接寻址或间接引用运算符
ip一般代表的是指向int的指针,下面为ip的声明:
int *ip;
这样生命是为了记忆,该声明语局表明表达式*ip的结果时int类型。这种声明变量的语法与声明变量所在表达式的语法类似。同样的原因,对函数的声明也可以采用这种方法。例如:声明:
double *dp, atof(char *);
在表达式中,*dp和atof(s)的值都是double类型,且atof的参数是一个指向char类型的指针
我们应当注意,指针只能指向某种特定类型的对象,也就是说,每个指针都必须指向某种特定的数据类型。(但是void类型的指针可以存放指向任何类型的指针,但他不能间接引用自身)
*ip = *ip + 10;
*ip的值增加10 *和&的优先级最高
++*ip //等同
*ip += 1
是将ip指向的对象的值加1
但是(*ip)++和*ip++则不同,其中前者与上述代码同意,但后者则是对指针加1。*和++这种运算符遵循从右到左的结合律。
最后,由于指针也是变量,所以在程序中可以直接使用,而不必通过间接引用的方法使用,
iq = ip;
讲吧ip的值拷贝到iq中,即iq也指向ip指向的对象。
##指针与数组
对数组元素a[i]的引用也可以写成*(a + i)的形式,C语言实际上就是这样转换后然后再进行求值,同理,&a[i], a+i也是等价的,a+i是a之后第i个元素的地址,如果pa是一个指针,也可以用pa[i]来取值。
但是,我们必须记住,数组名和指针有一个地方不同,指针是一个变量,因此在C中,语句p=a和pa++都是合法的。但数组名不是变量!
当数组名传递给一个函数时,实际上传的是该数组第一个元素的地址。在被调用函数中,该参数是一个局部变量, 因此,数组名参数必须是一个指针,也就是一个存储地址值的变量。
在函数定义中,形式参数:
char s[];
和
char *s;
是等价的。我们通常更习惯于后一种形式,因为他比前者更简洁明了表明了s是一个指针。如果将数组名传给函数,函数可以按照情况判定是按照数组处理还是按照指针处理,
##地址算术运算
指针与整数不能相互转换,但0是唯一的例外:常量0可以赋值给指针,指针也可以和常量0进行比较。程序中常用NULL代替9
p + n ;
p + sizeof(type℗) * n; // 等同
##字符指针与函数
字符串常量是一个字符数组,字符串常量最常见的用法是当做函数参数传递。
下面两个定义之间有很大的区别:
char amessage[] = "now is the time"// 定义一个数组
char *pmessage = "now is the time"// 定义一个指针
上述声明中,amessage是一个仅仅足以存放初始化字符串及空字符的一维数组,数组中单个字符可以修改,但amessage始终指向同一个存储位置。另一方面,pmessage是一个指针,其初值指向一个字符串常量,之后它可以被修改以指向其他地址,但如果试图修改字符串的内容,结果是没有定义的:
这图反了。。。大家尽量看
++与*搭配使用:
*p++ = val // 压栈
*--p = val // 出栈
##多维数组
如果二维数组作为参数传递给函数,那么在函数的参数声明中必须指明数组的列数,数组的行数则没有太大关系,因为前面已经讲过,函数参数传递的是一个指针,他指向由行向量组成的一维数组,其中每个行向量是13个整形元素构成的一维数组。在该例子中,传递给函数的是一个只想很多对象的指针,其中每个对象为13个整形元素构成的一维数组。
f(int (*daytab)[13]);
f(int daytab[][13]);
f(int daytab[2][13]);
这三种声明方式实际上是一致的。
第一种中,表示参数是一个指针,它指向具有13个元素的一维数组。因为方括号[]的优先级高于*的优先级,如果去掉括号,则变成:
f(int *daytab[13])
这相当于声明了一个数组,该数组有13个元素,其中每个元素都是一个指向整型的指针。
一般来说,除数组中的第一维可以不指定下标外,其他都必须指定下标。
##指针与多维数组
int a[10][20];// 多维数组
int *b[10];// 指针数组
指针数组的一个重要优点在于,数组的每一行的长度可以不同,也就是说,b的每个元素不必都指向一个具有20个元素的向量,某些元素可以指向2个元素的向量。
指针数组的最常用的领域是存放不同长度的字符串,
char *name[] = {…};// 指针数组
char name[][15];// 二维数组