C程序设计语言04|C程序设计语言04 - 指针与数组

指针是保存变量地址的变量
0x00 指针与地址 一元运算符&可用于取一个对象的地址,如: p = &c; , 把变量c的地址赋值给变量p,称p为“指向”c的指针。地址运算符&只能应用于内存中的对象,即变量和数组元素,不能作用于表达式、常量或register类型的变量。
【C程序设计语言04|C程序设计语言04 - 指针与数组】一元运算符*是间接寻址或间接引用运算符。作用于指针时,将访问指针所指向的对象。
指针声明: int *p; ,该语句表明表达式*ip的结果是int类型。
0x01 指针与函数参数 由于C语言是以传值的方式将参数值传递给被调用函数,所以调用函数不能直接修改主调函数中变量的值。可以使主调程序将指向所要改变的变量的指针传递给调用函数,这样被调函数可以改变主调函数变量的值。
如:

void swap(int *px, int *py) { int temp; temp = *px; *px = *py; *py = temp; }

0x02 指针与数组 通过数组下标所能完成的任意操作都可以通过指针来实现。一般来说用指针编写的程序比用数组下标编写的程序执行速度快。
“指针加1”意味着指针所指向对象的下一个对象。
数组类型的变量或表达式的值是该数组第0个元素的地址。
int *pa, a[10]; pa = &a[0]; pa = a; //等价于pa = &a[0];

一个通过数组和下标实现的表达式可等价地通过指针和偏移量实现。数组名和指针之间的不同之处在于指针是一个变量,而数组名不是,指针可以改变,而数组名不行。
当把数组名传递给一个函数时,实际上传递的是该数组的第一个元素的地址。
在函数定义中,形式参数char s[]char *s是等价的。
0x03 地址算术运算 有效的指针运算包括
  1. 相同类型指针之间的赋值运算
  2. 指针同整数之间的加法和减法运算
  3. 指向相同数组中元素的两个指针间的减法或比较运算
  4. 将指针赋值为0或指针与0之间的比较运算
0x04 字符指针与函数 字符串常量是一个字符数组。字符串常量可以通过一个指向其第一个元素的指针访问。如:
char *pmessage; pmessage = "now is the time";

0x05 指针数组以及指向指针的指针 指针数组声明
char *lineptr[MAXLINES];

*lineptr[0] 等价于 **ilneptr,前者是是一个指针数组,后者是指向指针的指针,但底层是一样的,因为int a[]; a[0] == *a
0x06 多维数组 二维数组是一种特殊的一维数组,它的每个元素也是一个一维数组。
如果将二维数组作为参数传递给函数,在函数的参数声明中必须指明数组的列数。
一般来说,除数组的第一维可以不指定大小外,其余各维都必须明确指定大小。
注意:
// 下面三种声明作用相同 f(int daytab[2][13]) { ... } f(int daytab[][13]) { ... } f(int (*daytab)[13])

0x07 指针数组初始化
char *month_name(int n) { satic char *name[] = { "Illegal month", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; ... }

0x08 指针数组与多维数组
int a[10][20]; int *b[10];

a是一个真正的二维数组,它分配了200个int类型长度的存储单元。b定义仅仅分配了10个指针,并且没有初始化。指针数组的一个重要的优点在于,数组的每一行长度可以不同。
0x09 命令行参数
main(int argc, char *argv[]) // argc表示参数数量,argv是参数的指针数组,程序本身是第一个参数

0x10 指向函数的指针 函数本身不是变量,但可以定义指向函数的指针。
// 函数定义 void qsort(void *lineptr[], int left, int right, int (*comp)(void *, void *)); // 函数调用 qsort((void**) lineptr, 0, nlines-1, (int (*)(void*, void*))(numeric ? numcmp : strcmp));

strcmp和numcp是函数地址, 函数不需要使用地址运算符&取值,同数组一样。
通用指针类型void *, 任何类型的指针都可以转换为void *类型,并且在将它转换回原来的类型时不会丢失信息。
int (*comp)(void *, void *))声明中表明comp是一个指向函数的指针,*comp代表一个函数。(*comp)(v[i], v[left])是对指针函数的调用,其中圆括号必须。

    推荐阅读