地址运算符&只能应用于内存中的对象,即变量与数组元素。它不能作用于表达式、常量或register类型的变量。
运算优先级
一元运算符*和&的优先级比算术运算符的优先级高。
*ip += 1
++*ip
(*ip)++
语句(ip)++中的圆括号是必需的,否则,该表达式将对ip进行加一运算,而不是对ip指向的对象进行加一运算,类似于\和++这样的一元运算符遵循从右至左的结合顺序。
传值的方式将参数值传递给被调用函数。传引用使用&
// array_address.c
char *str = "hello";
printf("[begin] str %s\n", str);
test_array_name(str);
printf("[end] str %s\n", str);
void test_array_name(char *s) {
printf("[in] str %s\n", ++s);
}
void test_array_name1( char &s) {
}
/* out
>> [begin] str hello
>> [in] ca[] ello
>> [end] str hello
*/
通过数组下标所能完成的任何操作都可以通过指针来实现。用指针编写的程序比用数组下标编写的程序执行速度快。
指针加1意味着,pa+1指向pa所指向的对象的下一个对象。
在计算数组元素a[i]的值时,实际上先将其转换为*(a+i)的形式。通过数组和下标实现的表达式可等价地通过指针和偏移量实现。
数组名和指针之间有一个不同之处。指针是一个变量,所以pa=a和pa++是合法的。但数组名不是变量,因此a=pa和a++形式的语句是非法的。由此可以推断,当把数组名传递给一个函数时,实际上传递的是该数组第一个元素的地址。函数由此地址生成了一个局部变量。
main
{
char ca[] = "hello";
printf("[begin] ca[] %s\n", ca);
test_array_name(ca);
printf("[end] ca[] %s\n", ca);
}
void test_array_name(char s[])
{
s++;
printf("[in] ca[] %s\n", s);
}
out:
>> [begin] ca[] hello
>> [in] ca[] ello
>> [end] ca[] hello
函数定义中,形式参数 char s[]和char *s是等价的,习惯用后一种形式,它直观地表明了该参数是一个指针。
p[-1]、p[-2]这样的表达式在语法上都是合法的,它们分别引用位于p[0]之前的两个元素。
#define ALLOCSIZE 1000
static char allocbuf[ALLOCSIZE];
static char *allocp = allocbuf;
char * alloc(int n)
{
if (allocbuf + ALLOCSIZE - allocp >= n) {
allocp += n;
return allocp - n;
} else
return 0;
}
void afree(char *p)
{
if (p >= allocbuf && p < allocbuf + ALLOCSIZE)
allocp = p;
}
对指针有意义的初始化值只能是0或者是表示地址的表达式。
指针与整数之间不能相互互换,但0是唯一的例外:常量0可以赋值给指针,指针也可以和常量0进行比较。程序中经常用符号常量NULL代替常量0,这样便于更清晰地说明常量0是指针的一个特殊值。
0不是有效的数据地址,所以经常用代表0的符号常量NULL来判别指针是否有效。
如果指针p和q指向同一个数组的成员,那么它们之间就可以进行类似与==、!=、<、>=的关系比较运算。
指针的减法是有意义的:如果p和q指向相同数组中的元素,且p<q,那么q-p+1就是位于p和q指向的元素之间的元素的数目。
int strlen(char *s)
{
char *p = s;
while (*p != '\0')
p++;
return p -s;
}
有效的指针运算:
// 两个定义之间有很大差别
char amessage[] = "now is the time";
char *pmessage = "now is the time";
指针本身也是变量,所以它们也可以像其他变量一样存储在数组中。
一个对字符串数组排序的例子。
作为参数传递给函数,在函数参数声明中必须指明数组的列数。
f(int daytab[2][13])
f(int daytab[][13])
f(int (*daytab)[13])
int a[10][20];
int *b[10];
a分配了200个int类型长度的存储空间,用20xrow+col计算得到元素a[row][col]的位置。
b仅仅分配了10个指针,并且没有对它们初始化。
指针数组的一个重要优点在于,数组的每一行长度可以不同。
argc为运行程序时命令行中参数的数目 argv是一个指向字符串数组的指针,其中每个字符串对应一个参数。argv[argc]为空指针。
echo hello, world
argc 3
argv ["echo", "hello,", "world", 0]
++argv 是指向"hello"的指针 (++argv)[0] 是'h', 等效为*++argv []与操作数的结合优先级比和++高 ++argv[0] 为++(argv[0])目的是遍历一个特定的参数串
声明
int (*comp)(void *, void*)
使用
int fun(int x, int *p);
comp = fun;
int y = 1;
(*comp)(3, &y);
comp(3, &y);
函数指针的值是该函数机器代码表示中第一条指令的地址