一.前言
指针的概念:
- 指针就是个变量,用来存放地址,地址唯一标识一块内存空间
- 指针的大小是固定的4/8个字节(32位平台/64位平台)
- 指针是有类型的,指针的类型决定了指针的+-整数的步长,指针解引用操作的权限
二.字符指针&字符数组&字符串
字符数组就是元素为字符变量的数组,而字符串则是以'\0'(ASCii码值为0x00)为结束字符的字符数组.字符数组并不一定是字符串.
'\0':用来标记字符串的结束
int main() {
//一般使用方法:
char ch = 'f';
char* pc = &ch;
//另一种使用方法:
const char* pstr = "asdfgh";
cout << pstr << endl; //输出:asdfgh
cout << *patr << endl; //输出a
return 0;
}
代码char* pstr = "asdfgh"特别容易让我们认为是把字符串asdfgh放到了字符串指针pstr里了,但是本质是把字符串asdfgh首字符的地址放到了pstr中.
因为由于字符串的连续性,编译器没有必要通过它的长度信息来提取整个字符串,仅通过一个指向其开头字符的字符指针就能实现对整个字符串的引用.
存在的问题:
对于字符数组来说,它并不在于中间或者末尾有没有'\0'结束字符,因为数组知道它有多少个元素,况且'\0'字符对它来说是一个合法的元素. 问题在于:可能会把字符数组当做字符串使用,可能会使用字符指针(char* p)引用一个字符数组.在这种情况下,使用库函数(strcpy,strlen等)对字符串(实际是字符数组)操作时,就会出现危险: 如果此时字符数组没有'\0'结束标志,那么把它当做字符串使用时就会导致越界访问.
面试题解析:先上代码先上代码!!!
int main() {
char str1[] = "asdfgh";
char str2[] = "asdfgh";
const char* str3 = "asdfgh";
const char* str4 = "asdfgh";
if (str1 == str2) {
cout << "str1 and str2 are same" << endl;
}
else {
cout << "str1 and str2 are not same" << endl;
}
if (str3 == str4) {
cout << "str3 and str4 are same" << endl;
}
else {
cout << "str3 and str4 are not same" << endl;
}
return 0;
}
程序输出:
解析: str3和str4指向的是同一个常量字符串.C/C++会把常量字符串存储到单独的一个内存区域,当几个指针指向同一个字符串的时候,它们实际会指向同一块内存.但是用相同的常量字符串去初始化不同的数组的时候就会开辟不同的内存块.
三.数组指针
顾名思义,也就是能够指向数组的指针.
int (*p)[10];
解释:p先和*结合,说明p是一个指针变量,然后指向的是一个大小为10个整形的数组.因此p是一个指向数组的指针,称之为数组指针.
四.指针数组
顾名思义,就是存放指针变量的数组.
int* p[10];
解释:[]的优先级高于*,因此p先和[]结合,说明p是数组,保存的是10个int*类型的指针变量,称之为指针数组.
数组指针与指针数组的对比:
五.函数指针
int (*p)(int);
解释:p先和*结合,说明p是指针,指向的是一个函数,指向的函数的参数为int类型,返回值类型为int类型
typedef int(*p)(int);
解释:typedef的功能是定义新的类型.即定义了一种p的类型,并定义这种类型为指向某种函数的指针.这个函数以一个int类型为参数,并且返回int类型.
使用方法:
typedef int(*handle)(int, int);
int add(int a, int b) {
return a + b;
}
int main() {
handle t = add;
cout << t(2, 4) << endl;
cout << (*t)(2, 4) << endl;
return 0;
}
六.函数指针数组
数组是存放相同类型数据的存储空间. 因此函数指针数组中存放的都是函数指针.
int (*p[10])();
解释:因为[]的优先级高于*,所以p先和[]结合,表明是一个数组.数组中存储的是int (*)()类型的函数指针.
函数指针数组的用途:转移表
七.指向函数指针数组的指针
顾名思义,指向函数指针数组的指针是一个指针,指针指向一个数组,数组中的元素都是函数指针.
void (*(*p)[10])(const char*);
解释:p先和*结合,表明是一个指针.(*p)和[]结合,表明是一个指向数组的指针.数组中存储的是void(*)(const char*)类型的函数指针.
八.回调函数
回调函数就是一个通过函数指针调用的函数.如果把函数的指针作为参数传递给另一个函数,当这个指针被用来调用其所指的函数时,我们就说这是回调函数.回调函数不是由该函数的实现方直接调用的,而是在特定的事件或条件发生时由另外的一方调用,用于该事件或条件进行响应.
九.&数组名VS数组名
int arr[] = {1,2,3};
数组名(arr)表示的是数组首元素的地址.
&数组名(&arr)表示的是数组的地址(数组指针),而不是数组首元素的地址.
数组的地址(数组指针)+1:即跳过整个数组的大小