1.野指针可能带来哪些后果?
野指针,即指向一个错误位置的指针,如果你的程序中有野指针,你的数据就危险了。存放在堆中的数据可能会被破坏,用来处理堆的数据结构也可能被破坏,甚至操作系统的数据也可能被修改,甚至有时上述三种破坏情况同时发生。
此后可能发生的事情取决与这样两点:第一,内存中的数据被破坏的程度有多大;第二,内存中的被破坏的部分还要被使用多少次。在有些情况下,一些函数将立即无法正常工作;在另一些情况下,程序会终止并报告一条出错消息,或者程序可能会挂起,或者程序可能会陷入死循环,或者程序可能会产生错误的结果,或者程序看上去仍然正常运行,因为程序没遭到本质的破坏。
2.常量指针与指针常量
(1) const char *p;
(2) char* const p;
(3) char *p = "abc";
语句(1)第一了一个常量指针,即指向一个常量的指针,指向的内容是常量,不可以修改,放在常量区的,但指针本身可以修改,即“*p=‘b’”是非法的,*p是p指向的常量的第一个字符,是个常量,不能改变的。“p=&q”这是可以的,指针可以指向不同的地址。
语句(2)定义了一个指针常量,即指针本身是个常量,不可修改,但指针指向的内容可以修改,一开始定义时让它指向数组a,“*p=‘b’”这是可一个,但“p=&b”是非法的。
const常量*指针,当const在*之前就是常量指针,而const在*之后就是指针常量。例如“const char*p”即char*p是个常量,所以内容是常量;“char* const p;”即指针p是个常量。
语句(3)中“char *p”定义的是一个指针变量p,指向字符串abc首地址。这里特别要注意,在C语言中,(3)中定义的是一个常量字符串,它被放在静态存储区的常量区存储,而p是一个指针变量,放在栈上。如果“*p=‘b’”在编译时能通过,但在运行时就会出现错误,因为你识图去改变常量区的内容。
3.空指针的三种用法
(1)用空指针终止对递归数据结构的间接引用。
(2)用空指针进行函数调用失败时的返回值。
(3)用空指针作警戒值。
4.指针数组和数组指针
指针数组“typename *p[n]”定义了一个数组,数组包含了n个指针变量p[0],p[1],…,p[n-1]。符合一般数组的特性,除了数组中的元素是指针以外,和一般的数组没什么区别。数组名p是个指针常量,不能直接进行指针运算,不过可以传递给函数来进行。可以通过“p[x]”来对指针数组进行赋值,如“p[2] = "hijklm";”,否则,对数组中的每个指针进行初始化,必须先分配p[x]锁指向的内存空间!必须对分配结果进行判断。
指向数组的指针(以二维数组为例),二维数组“int[2][4]”,可以看作有两个num[4]的数组构成,数组名指向第一个元素,num[0]指向{num[0][0],num[0][1],,,num[0][3]},num=num[0]=&num[0][0];num+1=num[1]=&num[1][0];二维数组名可以看做一个指向指针数组的指针。
5.指针函数和函数指针
(1)函数指针:即指向这个函数的指针,定义为“数据类型(*fun)(参数列表);”,()的优先级比*高,所以*fun加括号,如"void (*fun)(int *,int*);";
(2)指针函数:即返回值是指针的函数,定义为“数据类型 *fun(参数列表);”,如“char *fun(int*, int*);”,即返回值为char* 型。
6.指针函数的返回值问题
当函数的返回值为指针类型时,应该尽量不要返回局部变量的指针,因为局部变量是定义在函数内部,当这个函数调用结束了,局部变量的栈内存也被释放了,因此不能够正确地得到返回值。实际上,内存已经被释放了,但这个指针的地址已经返回过去了,但是这个地址已经是无效的了,此时,对这个指针的使用是很危险的。
7.左右法则
右左法则:首先从最里面的圆括号内未定义的标识符开始阅读看起,然后往右看,再往左看。每当遇到圆括号时,就应该掉转阅读方向。一旦解析完圆括号里面所有的东西,就跳出圆括号。重复这个过程直到整个声明解析完毕。
在通过复杂例子解析左右结构之前,我先说一下指针数组嵌套中的一些基本类型
1.int a; 整形变量
2.int *a; 整形指针变量
3.int **a; 整形指针的指针变量(一个指向指针的指针,它指向的指针指向一个整形数)
4.int a[10]; 整形数组
5.int *a[10]; 整形指针数组(一个数组中有10个指针,该指针指向一个整形数)
6.int (*a)[10]; 整形数组指针(一个指向有10个整形数组的指针)
7.int (*a)(int); 函数指针变量(一个指向函数的指针,该函数有一个整形参数并返回一个整形数)
8.int (*a[10])(int); 函数指针数组(一个有10个指针的数组,该指针指向一个函数,该函数有一个整形参数并返回一个整形数)
介绍完一些基本类型,下面来介绍一些复杂的例子
1.int *( * ( *fpl ) ( int ) ) [10];
--*fpl 知道fpl是一个指针
--*(*fpl)(int) 知道指针fpl指向一个形参为int,返回值为指针的函数
--int *(*(*fpl)(int))[10] 知道该函数的指针指向一个数组,该数组有10个元素,并且每个元素指向一个整数
总结:fpl被声明为一个函数的指针,该函数返回值是一个指向指针数组的指针。
8.字符串函数
1. strcpy
原型:char *strcpy (char * __dest, const char * __src);
功能:将一个字符串(__src
)拷贝到另一个字符串缓冲区中(__dest
),并返回拷贝后的字符串指针;
2. strncpy
原型:char *strncpy (char * __dest, const char *__src, size_t __n);
功能:将一个字符串(__src
)拷贝到另一个字符串缓冲区中(__dest
),拷贝最多不超过__n
字节,并返回拷贝后的字符串指针;
3. strcat
原型:char *strcat (char *__dest, const char *__src);
功能:将一个字符串(__src
)拼接到另一个字符串缓冲区中(__dest
),并返回拼接后的字符串指针;
4. strncat
原型:char *strncat (char *__dest, const char *__src, size_t __n);
功能:将一个字符串(__src
)拼接到另一个字符串缓冲区中(__dest
),最多不超过__n
个字节,并返回拼接后的字符串指针
5. strlen
原型:size_t strlen (const char *__s);
功能:返回一个字符串(__src
)的长度,即字节(符)数,这里仅考虑ASCII字符;
6. strcmp
原型: int strcmp (const char *__s1, const char *__s2);
功能:比较字符串__s1
和字符串__s2
,返回比较结果,如果相等,则返回0;
比较方式:两个字符串自左向右逐个字符相比(按ASCII值大小相比较),直到出现不同的字符或遇’\0’为止;
返回结果:当s1<s2
时,返回值<0;当s1=s2
时,返回值=0;当s1>s2
时,返回值>0;
7. strncmp
原型: int strncmp (const char *__s1, const char *__s2, size_t __n);
功能:比较字符串__s1
和字符串__s2
的__n
个字符,返回比较结果,如果相等,则返回0;
比较方式:同strcmp;
返回结果:同strcmp;
8. strcasecmp
原型: int strcasecmp (const char *__s1, const char *__s2);
功能:比较字符串__s1
和字符串__s2
,忽略大小写的比较,返回比较结果,如果相等,则返回0;
9. strncasecmp
原型: int strncasecmp (const char *__s1, const char *__s2, size_t __n);
功能:比较字符串__s1
和字符串__s2
的__n
个字符,忽略大小写的比较,返回比较结果,如果相等,则返回0;
9.万能指针void