指针与地址
- 一元运算符&可用于取一个对象的地址,地址运算符&只能应用于内存中的对象,即变量与数组元素。不能作用于表达式、常量或者register类型的变量。
p = &c;
- 一元运算符* 是间接寻址或间接引用运算符。当它作用于指针时,将访问指针所指向的对象,下面代码段说明了程序中如何使用&和*:
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] */
-
int * ip ,该声明表明表达式*ip的结果是int类型。
-
指针只能指向某种特定类型的对象(一个类外是指向void类型指针可以存放指向任何指针,但他不能间接引用自身)
-
一元运算符*和&的优先级比算术运算符的优先级高。但是下面表达式中圆括号是必须的,否则,该表达式将对ip进行加1运算,这是因为,类似于 *和++这样的一元运算符遵循从右至左的结合顺序。
(*ip)++
- 指针也是变量,所以程序中可以直接使用,不用通过间接引用的方法使用。若iq是另一个指向整型的指针,那么下式表示将ip的中的值拷贝到iq中,指针iq也指向ip指向的对象。
指针与函数参数
由于c语言以传值的方式将参数传给被调用函数。因此,被调函数不能直接修改主调函数中变量的值。可以将参数申明为指针,通过指针来间接访问他们指向的操作数。
void swap(int *px, int *py) /* interchange *px and *py */
{
int temp;
temp = *px;
*px = *py;
*py = temp;
}
指针与数组
指针和数组在C语言中是紧密相关的。任何可以用数组下标做的事情都可以用指针做。一般来说,用指针编写的程序执行速度比用数组下标编写的程序快,但另一方面,用指针编写的程序稍微难以理解。
声明数组,定义一个长度为为10的数组a
int a[10]
a[i]表示该数组的第i个元素,定义一个int类型的指针,将该指针指向数组的第0个元素
int *pa = &a[0]
也就是说,pa的值为数组元素a[0]的地址。如果pa指向数组中的某个特定元素,那么,根据指针运算的定义,pa+1将指向下一个元素,如下图
无论数组a中的元素类型或数组的长度如何,这都是正确的。“指针加1”表示pa+1指向pa所指向的对象的下一个对象。因此,pa+i指向pa所指向的对象之后的第i个对象。
根据定义,数组类型的变量或者表达式的值是该数组第0个元素的地址
pa = &a[0];
执行上面语句后,pa和a具有相同的值。因为数组名所代表的就是该数组最开始的一个元素的地址,所以,赋值语句 pa=&a[0] 也可以写成
pa = a;
对数组元素a[i]的引用也可以写成 *(a+i) 这种形式。a+i 是 a 之后第 i 个元素的地址。相应的,如果pa是个指针,那么,在表达式中可以给它的后面加下标。pa[i] 和 *(pa+i) 等价。
数组名和指针之间有一个不同之处,指针是一个变量,因此,语句 pa=a 和 p++ 都合法,但数组名不是变量,类似于 a=pa 和 a++ 形式的语句都是非法的。
指针与算术运算
- 指针与整数之间不能转换,0是例外:常量0可以赋值给指针,指针也可以和常量0进行比较。程序中常用符号常量NULL代替常量0,这样便于更加清晰地说明常量0是指针的一个特殊值。符号常量NULL定义在标准头文件<stddef.h>中。
- 在某种情况下还可以对指针进行比较运算。如:若指针p和q指向同一个数组的成员,那么他们之间可以进行类似于 == 、 != 、 < 、>= 等比较运算。若p指向的位置在q之前,那么关系表达式 p < q 为真。
- 任何指针与 0 进行相等或不相等的比较都有意义。
- 指针可以和整数进行相加或相减运算。
- 指针的算术运算具有一致性:指针算术运算后结果还是该类型的指针。
有效的指针运算包含:
①相同类型指针之间的赋值运算,指针同整数之间的加法或者减法运算;
②指向相同数组中元素的两个指针之间的加减法运算或比较运算;
③将指针赋值为0或指针与0之间的比较运算。其他所有形式的指针运算都是非法的。
字符指针与函数
字符串常量是一个字符数组,在字符串的内部表示中,字符数组以空字符 '\0' 结尾,故,程序可以通过检查空字符找到字符数组的结尾。
- 字符串常量作为函数参数
princf("你好,世界!\n");
当类似于这样一个字符串出现在程序中时,实际上是通过字符指针访问该字符串的。上数代码中,princf函数接受一个指向字符数组第一个字符的指针。
- 将字符串常量赋值该字符指针
char amessage[] = "nw is the time"; /* 定义一个数组 */
char *pmessage = "now is the time"; /* 定义一个指针 */
char *pmessage = "now is the time" 将一个指向字符数组的指针赋值给pmessage。该过程没有字符串赋值,只有指针操作。C语言没有提供将整个字符串作为一个整体进行处理的运算符。
上述声明中,amessage是一个仅仅足以存放初始话字符串以及空字符'\0'的一维数组。数组中单个字符可以进行修改,但amessage始终指向同一存储位置。pmessage是一个指针,其初始值指向一个字符串常量,之后它可以修改以指向其他地址,但是视图修改字符串的内容,结果没有定义。
实现strcpy函数 数组方式实现
/* strcpy: copy t to s; array subscript version */
void strcpy(char *s, char *t)
{
int i;
i = 0;
while ((s[i] = t[i]) != '\0')
i++;
}
指针方式实现
/* strcpy: copy t to s; pointer version */
void strcpy(char *s, char *t)
{
int i;
i = 0;
while ((*s = *t) != '\0') {
s++;
t++;
}
}
有经验的程序员更倾向于这样
/* strcpy: copy t to s; pointer version 2 */
void strcpy(char *s, char *t)
{
while ((*s++ = *t++) != '\0')
;
}
为了更进一步提炼程序,我们注意到,表达式同'\0'比较是多余的,因为需要判断表达式的值是否为0即可。
/* strcpy: copy t to s; pointer version 3 */
void strcpy(char *s, char *t)
{
while (*s++ = *t++)
;
}
实现strcmp函数 数组方式
/* strcmp: return <0 if s<t, 0 if s==t, >0 if s>t */
int strcmp(char *s, char *t)
{
int i;
for (i = 0; s[i] == t[i]; i++)
if (s[i] == '\0')
return 0;
return s[i] - t[i];
}
指针方式
/* strcmp: return <0 if s<t, 0 if s==t, >0 if s>t */
int strcmp(char *s, char *t)
{
for ( ; *s == *t; s++, t++)
if (*s == '\0')
return 0;
return *s - *t;
}