先看以下例子:

int a[10]; int *pa = &a[10]; pa ;

首先指针pa指向a[0]的地址,注意后缀运算符的优先级高于单目运算符,所以是取a[0]的地址,而不是取a的地址。然后pa 让pa指向下一个元素(也就是a[1]), 由于pa 是int* 指针,一个int 型元素占4个字节,所以pa 使pa 所指向的地址加4,注意不是加1。

用方框表示存储空间,用箭头表示指针和变量之间的关系:

c语言指针和数组知识点总结(LinuxC编程)(1)

既然指针可以用 运算符,当然也可以用 , - 运算符,pa指向a[1],那么pa 2指向a[3]。

*(pa 2)也可以写成pa[2],pa就像数组名一样,a[2]之所以能取数组的第二个元素,是因为它等于*(a 2),当数组名做右值时自动转换成指向首元素的指针,所以a[2]和pa[2]本质上是一样的,都是通过指针间接寻址访问元素。

由于a做右值使用时和&a[0] 是一个意思,所以 int *pa = &a[0]; 通常不这么写, 而是写成更简洁的形式: int *pa = a;

在函数原型中,如果参数是数组,则等价于参数是指针的形式,例如:

void func(int a[10]) { ... }

第一种形式的方括号中的数字可以不写,仍然是等价的:

void func(int a[]) { ... }

参数写成指针形式还是数组形式对编译器来说没有区别,都表示这个参数是指针,之所以规定两种形式是为了给代码的人提供有用的信息,如果这个参数指向一个元素,通常写成指针的形式,如果这个参数指向一串元素中的首元素,则通常写成数组的形式。

(*p) , 先传值,后值自增1,类比a

*p == *(p ), 先传值,后地址自增1

*p == (*p), 值先自增1,后传值,类比a

* p == *( p), 地址先自增1, 后传值

#include <stdio.h> int main() { int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int *pa = &a[0]; printf("*pa = %d\n", *pa); pa ; printf("*pa = %d\n", *pa); printf("*pa = %d\n", *( pa)); return 0; }

const限定符和指针结合起来常见的情况有以下几种:

const int *a; int const *a;

这两种写法是一样的,a是一个指向const int 型的指针,a 所指向的内存单元不可改写,所以(*a) 是不允许的,但 a 可以改写,所以a 是允许的。

int * const a;

a 是一个指向int 型const 指针,*a 是可以改写的,但a不允许改写。

int const * const a;

a 是一个指向const int 型的const 指针,因此*a 和 a 都不允许改写。

指向非const 变量的指针或者非const变量的地址可以传给指向const变量的指针,编译器可以做隐式类型转换,例如:

char c = 'a'; const char *pc = &c;

但是,指向const变量的指针或者const变量的地址不可以传给指向非const变量的指针,以免透过后者意外改写了前者所指向的内存单元,下面的代码编译器在编译时会报警告:

const char c = 'a'; char *pc = &c;

良好的编程习惯应该尽可能多地使用const, 有以下几个优点:

1. const 给代码的人传达非常有用的信息。比如一个函数的参数是 const char *, 或者是const int *, 在调用这个函数时就可以放心地传给它char * 或 const char * 指针, 而不必担心指针所指的内存单元被改写。 2. 尽可能多地使用const 限定符,把不该变的都声明为只读,这样可以依靠编译器检查程序中的Bug, 防止意外改写数据。 3. const 对编译器优化是一个有用的提示,编译器也许会把const 变量优化成常量。

字符串字面值通常分配在.rodata段,字符串字面值类似于数组名,当字面值作为右值使用时自动转换成指向首元素的指针,这种指针应该是co nst char * 型。printf 函数原型的第一个参数是const char *型,可以把char *或const char *指针传给它,参考下面的调用:

const char *p = "abcd"; const char str1[5] = "abcd"; char str2[5] = "abcd"; printf(p); printf(str1); printf(str2); printf("abcd");

如果要定义一个指针指向字符串字面值,这个指针应该是const char * 型,如果写成char *p = "abcd"; 会有被串改的隐患:

int main(void) { char *p = "abcd"; ... *p = 'A'; ... }

p 指向 .rodata 段,不允许改写,但编译器不会保存,在运行时出现段错误。

,