1、字符指针
字符指针的一般应用,获取地址之后解引用写入一个新的字符。
int main()
{
char a='w';
char* c=&a;
*c='c';
printf("%c ",a);
getchar();
return 0;
}
2、对一个字符指针输入一个字符串
将str str的首地址放到了str的指针中去,并不是把整个字符串放到了字符指针。
int main()
{
char* str="str str";
str="aaa aaa";
printf("str=%s\n",str);
getchar();
return 0;
}
常量字符串不能被修改,
如果是这样写程序就会整个崩溃掉。
笔试题:判断下面的输出
#include <stdio.h>
int main()
{
char str1[] = "hello bit.";
char str2[] = "hello bit.";
char *str3 = "hello bit.";
char *str4 = "hello bit.";
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");
return 0;
}
str1与str2的地址应该是不同的,相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。
str3与str4相同,他们两个只是存储了首元素的地址,是同一个字符串。
说明:C/C++会把常量字符串存储到单独的一个内存区域,当几个指针。指向同一个字符串的时候,他们实际会指向同一块内存。
3、指针数组
在《指针》章节我们也学了指针数组,指针数组是一个存放指针的数组。
复习一下,下面指针数组是什么意思?
int* arr1[10]; //整形指针的数组
char *arr2[4]; //一级字符指针的数组
char **arr3[5];//二级字符指针的数组
4、数组指针
指向数组的指针,
下面哪个是数组指针?
int* p1[10]; //指针数组
int (*p)[10];
int (*p)[10];
//解释:p先和*结合,说明p是一个指针变量,然后指着指向的是一个大小为10个整型的数组。所以p是一个指针,指向一个数组,叫数组指针。
//这里要注意:[]的优先级要高于*号的,所以必须加上()来保证p先和*结合。
5、&数组名VS数组名
前面写过
除了两种情况其他所有情况数组名都是首元素地址
&arr:数组的地址,和首元素地址相同但是+1之后会跳过整个数组
sizeof(arr):数组的大小
6、数组指针的使用
存储数组的地址:直接存储数组地址,如下代码,但是一般不这样使用,本来可以很简单的打印没必要这么麻烦
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
int (*p)[10] = &arr;//把数组arr的地址赋值给数组指针变量p
int i=0;
for(i=0;i<10;i++)
{
printf("%d ",(*p)[i]);
}
for(i=0;i<10;i++)
{
printf("%d ",*((*p)+i));
}
printf("%p\n",(*p));
printf("%p",arr);
//但是我们一般很少这样写代码
getchar();
return 0;
}
可以通过解引用找到数组名,这时候数组名就是首元素地址,
1、可以直接使用(*p)[] 先对p解引用找到arr,这时候就是arr所以可以和【】直接组合
2、*((*p)+i) 先对p解引用找到arr,这时候arr单独出现就代表首元素地址,直接对其++就能跳到下一个元素的地址,再对其解引用。
没什么意义,可以直接拿一个整型指针存储arr首元素地址直接打印没必要这么麻烦,如下
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
int* pi=arr;
int i=0;
for(i=0;i<10;i++)
{
printf("%d ",*(pi+i));
}
getchar();
return 0;
}
一个数组指针的使用实例
void print_arr1(int arr[3][5], int row, int col)
{
int i = 0,j=0;
for(i=0; i<row; i++)
{
for(j=0; j<col; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
void print_arr2(int (*arr)[5], int row, int col)
{
int i = 0,j=0;
for(i=0; i<row; i++)
{
for(j=0; j<col; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
int main()
{
int arr[3][5] = {1,2,3,4,5,6,7,8,9,10};
print_arr1(arr, 3, 5);
//数组名arr,表示首元素的地址
//但是二维数组的首元素是二维数组的第一行
//所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
//可以数组指针来接收
print_arr2(arr, 3, 5);
getchar();
return 0;
}
只传了首行地址过去(首元素地址就是首行的),减小内存占用。
以下代码代表什么
int arr[5]; //数组 存放5个元素,每个元素为int
int *parr1[10]; //指针数组 是一个数组,每个数组的元素类型为int *
int (*parr2)[10]; //数组指针 是一个指针,指向一个有10个元素的数组,数组的每个元素为int
int (*parr3[10])[5]; //指针数组数组 是一个数组,每个数组存放的为int*[5],指向了一个数组,每个数组有5个int元素,
二维数组的传参
void test(int (*p)[5],int x,int y)
{
int i=0;
for(i=0;i<x;i++)
{
int j=0;
for(j=0;j<y;j++)
{
// printf("%d ",p[i][j]);
printf("%d ",*(p[i]+j));
// printf("%d ",*((*(p+i)+j)));
//printf("%d ",(*(p+i))[j]); //首地址为第一行 解引用了第一行地址
}
printf("\n");
}
}
int main()
{
int arr[3][5]={{1,2,3,4,5},{6,7,8,9,0},{1,2,3,4,5}};
test(arr,3,5);
return 0;
}
7.函数指针
指向函数的指针,通过指针找到函数地址,直接传参可以使用函数,看着没什么用,但是后面的函数指针数组和回调函数会有实际的使用场景。
int add(int x,int y)
{
return x+y;
}
int main()
{
//函数指针
int(*p)(int,int)=add;
printf("%d\n",p(3,5));
return 0;
}
8. 函数指针数组
存放函数指针的数组:存放同类输入与返回函数的数组
通过数组存放函数指针,然后可以直接找到每个函数,就不用写个switch每次打印了
int add(int x,int y)
{
return x+y;
}
int sub(int x,int y)
{
return x-y;
}
int main()
{
int x,y;
int input=1;
int ret=0;
//函数指针数组
int(*(p[3]))(int,int)={0,add,sub};
while(input)
{
printf("---1.add---2.sub---\r\n");
scanf("%d",&input);
if(input>0&&input<3)
{
printf("please inptu:");
scanf("%d %d",&x,&y);
ret=(p[input])(x,y);
}
else
printf("erro\r\n");
printf("%d\n",ret);
}
return 0;
}
9.指向函数指针数组的指针:存放数组的地址,不过数组是一个函数指针数组
函数指针数组:int (*arr[5])(int,int);
指向函数指针数组的指针:int((*(*arr1))[5](int,int))=&arr;
10.回调函数
不由实现放去调用这个函数。
有一个函数去传入并在里面调用回调函数。和刚刚的函数指针数组
例子qsort: