目录
一.字符指针
字符指针char*是指针的一种类型。
int main()
{
char str1[] = "hello.";
char str2[] = "hello.";
const char * str3 = "hello.";//把一个常量字符串的首字符 h 的地址存放到指针变量中
const char * str4 = "hello.";
if (str1 == str2)
printf("str1 and str2 are same\n");
else
printf("str1 and str2 are not same\n");
if (str3 == str4)
printf("str3 and str4 are same\n");
else
printf("str3 and str4 are not same\n");
/str1与str2不相同 str3与str4相同
return 0;
}
这里str3和str4指向的是同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域,当 几个指针。指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化 不同的数组的时候就会开辟出不同的内存块。所以str1和str2不同,str3和str4不同。
二.指针常量和常量指针
指针常量(int*const p):指针本身是常量,就是指针里面所存储的内容(内存地址)是常量,不能改变。但是,内存地址所对应的内容是可以通过指针改变的。
常量指针(const int* p):指向常量的指针,就是指针指向的是常量,它指向的内容不能发生改变,不能通过指针来修改它指向的内容。但是,指针自身不是常量,它自身的值可以改变,从而指向另一个常量。
例:
int main() { int a = 10, int b = 20; int* p1 = &a; *p1 = 100;//正确 p1 = &b;//正确 const int* p2 = &a; *p2 = 100;//错误 p2 = &b;//正确 int* const p3 = &a; *p3 = 100;//正确 p3 = &b;//错误 const int* const p4 = &a; *p4 = 100;//错误 p4 = &b;//错误 return 0; }
是指针常量还是常量指针取决const的位置,const在 * 前就是常量指针,const在 * 后就是指针常量
知识串联:
int main()
{
const int n = 5;
int arr[n]={1,2,3,4,5} //错误
注意:在定义arr数组时[]内必须是常量,而在使用arr时[]内可以是变量
const int n 是常变量,本质是变量
return 0;
}
三.指针数组
指针数组是存放指针的数组,本质是数组,其中每个元素都是一个指针变量。
例如:
int* pa[10]; //整形指针的数组,存放整形指针
char *pb[4]; //一级字符指针的数组,存放一级字符指针
char **pc[5]; //二级字符指针的数组,存放二级字符指针
注意:以int* pa[10]为例,根据优先级,先看[ ],则pa是一个数组,再结合*,这个数组的元素是 int * ,共10个元素。
通过指针数组模拟二维数组:
int main() { int a[5] = {1,2,3,4,5}; int b[] = { 2,4,6,8,0}; int c[] = { 3,5,7,9,1 }; int* arr[3] = { a,b,c }; //不能用&数组名,取出的是整个数组的地址会报错 for (int i = 0; i < 3; i++) { for (int j = 0; j < 5; j++) { printf("%d ", *(arr[i] + j)); //等价于printf("%d ", arr[i][j]); } printf("\n"); } return 0; }
在这个例子中,int* arr[3] = { a,b,c }; 只能用数组名(首元素地址),不能用&数组名(整个数组的地址),取出的是整个数组的地址会报错
输出结果为:
知识串联:
关于数组名:数组名是数组首元素的地址,但是有2个例外:
1. sizeof (数组名)一 数组名表示整个数组,计算的是整个数组大小,单位是字节
2. &数组名一数组名表示整个数组,取出的是整个数组的地址
四.数组指针
数组指针是指向数组的指针,也是指针的一种类型。
举例:
int * 属于整型指针
char * 属于字符指针
int( * )[n]属于数组指针,是一个指针变量。注意 * 后加指针名字,n是常量,表明它指向了含有n个int类型元素的数组。
优先级问题:
()与[ ] 优先级相同,根据结合律,就从左向右运算。
()里是*p,先定义了指针,所以p是个指针,然后后面是[ ],才是数组,即数组指针。
例:
int main() { int arr[5] = { 1,2,3,4,5}; int(*p)[5] = &arr; printf("%d\n%d\n", (*p)[1],*(*p+1)); //2,2 printf("%d\n%d\n%d\n", *p, &arr,*( * p)); //*( * p)也可用**p表示 //*p中存放着数组的地址,*p解引得到数组地址,再解引得到数组元素 return 0; }
在这个例子中,int(*p)[5] = &arr;只能用&arr(取整个数组的地址才是数组指针),不能用arr(首元素的地址),部分编译器不会报错,但是会警告,“初始化”:“int (*)[5]”与“int *”的间接级别不同。
结合指针数组和数组指针的两个例子,要明白 指针数组中的指针指向的内容 和 数组指针指向的内容的区别
输出结果:
通过数组指针打印二维数组中的元素:
void my_print(int(*p)[5], int a, int b) { for (int i = 0; i < a; i++) { for (int j = 0; j < b; j++) { printf("%d ", *(*(p + i) + j));//等价于printf("%d ",p[i][j]); } printf("\n\n"); } } int main() { int arr[3][5] = { {1,2,3,4,5},{0,2,4,6,8},{1,3,5,7,9} }; my_print(arr, 3, 5); return 0; }
这个例子中指针加1,将跨过二维数组的一行。
输出结果:
区分下列指针类型:
int* parr1[5]; //存放整型指针的数组 int(*parr2)[5]; //数组指针,该指针指向一个数组,这个数组有5个元素,每个元素的类型是int int(*parr3[10])[5]; //parr3是一个存放数组指针的数组,该数组能够存放10个数组指针, //每个数组指针能够指向一个数组,每个数组有5个int类型的元素。