c语言指针用法详解,C语言指针笔记
Yyds干货库存
指针数组指针数组自变量和指针自变量函数指针数组指针指向函数指针数组指针回调函数指针和数组问题分析
一:字符指针
指针类型中的字符指针char*
#包含stdio.h
int main()
{
char* pa=再见;
//printf(%c\n ,* pa);//本质是将字符串第一个字符的地址存储在pa中
char* pa=再见;
char arr[]=再见;
printf(%s\n ,pa);
printf(%s\n ,arr);
返回0;
}
示例:
#包含stdio.h
int main()
{
char str 1[]= game ;
char str 2[]= game ;
//两个不同的数组,具有不同的新创建的空格
const char * str3= computer
const char * str4= computer
//常量字符串不能更改,只会保存一个副本,所以两个指针变量指向同一个地址。
if (str1==str2)
printf(str1和str2相同\ n );
其他
printf(str1和str2不相同\ n );
if (str3==str4)
printf(str3和str4相同\ n );
其他
printf(str3和str4不相同\ n );
返回0;
}
//str1和str2不相同
//str3和str4相同
二:数组指针(指向数组的指针)
1.数组指针
#包含stdio.h
int main()
{
int a=10
int * pa=a;//整形指针
char b= q
char * Pb=b;//字符指针
int arr[5]={1,2,3,4,5 };
int(* parr)[5]=arr;//因为[]的优先级高于*,所以需要括号。
}
从parr开始,用*组合,表示P是指针再用[],表示指针指向的内容是数组,再用int组合,表示数组中的元素是整数。所以parr是一个由整数数据组成的数组的指针。
(如何判断?看变量先和谁结合)
2:数组名和数组名
分别差4和40。
Arr取整个数组的地址,arr是数组第一个元素的地址。
3.应用
//二维数组
#包含stdio.h
void print1(int arr[3][5],int m,int n)
{
int I=0;
int j=0;
for(I=0;我是m;我)
{
int j=0;
for(j=0;j n;j)
{
printf(%d ,arr[I][j]);
}
printf( \ n );
}
}
//数组指针
void print2(int(*arr)[5],int r,int c)
{
int I=0;
for(I=0;I r;我)
{
int j=0;
for(j=0;j c;j)
{
printf(%d ,*(*(arri)j));
}
printf( \ n );
}
}
int main()
{
int arr[3][5]={ 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };
print1(arr,3,5);
print2(arr,3,5);
返回0;
}
//打印1,2
//1 2 3 4 5
//2 3 4 5 6
//3 4 5 6 7
注意:
int(* parr[10])[5];
//首先parr[10]是一个数组。帕尔[10]去掉后,就是尖型。
//parr是一个有10个数组指针的数组,可以容纳10个数组指针。
//每个数组指针都可以指向一个数组,这个数组有五个元素,都是int类型。
三:指针数组(存储指针的数组)
#包含stdio.h
int main()
{
//指针数组-指针(地址)存储在数组中
int a=10
int b=20
int c=30
int d=40
int* arr[5]={ a,b,c,d };
int I=0;
for(I=0;I 4;我)
{
printf( %d\n ,*(arr[I]));
}
} #包含stdio.h
int main()
{
int a1[]={ 1,2,3,4,5 };
int a2[]={ 2,3,4,5,6 };
int a3[]={ 3,4,5,6,7 };
int* arr[3]={ a1,a2,a3 };//表示每个数组的第一个元素的地址
int I=0;
for(I=0;i3;I )//行
{
int j=0;
for(j=0;j 5;J )//列
{
printf(%d ,*(arr[I]j));
//可以写成printf(%d ,arr[I][j]);
}
printf( \ n );
}
返回0;
}
//1 2 3 4 5
//2 3 4 5 6
//3 4 5 6 7
四:数组传递参数和指针传递参数
1:一维数组传递参数
#包含stdio.h
Void test1(int arr[10])//是
{}
Void test1(int arr[])//可以,元素个数可以省略
{}
Void test1(int* arr)//是,指针
{}
Void test2(int* arr[20])//可以,可以存储int*的整数指针数组
{}
Void test2(int** arr)//是,二级指针
{}
int main()
{
int arr 1[10]={ 0 };
int * arr 2[10]={ 0 };//保存int*的数组
test1(arr 1);
test 2(arr 2);//指向int*的第一个元素的地址
}
2.二维数组传递参数
只需填写参数的数组名。
参数可以是二维数组或指针。
//二维数组
Void test(int arr[3][5])//是
{}
Void test(int arr[][])//错误。可以省略行,但不能保存列。
{}
Void test(int arr[][5])//Yes
{}
//指针
Void test(int* arr)//没门。接收第一行的地址。第一行是五个整数的数组,不能用指针接收。
{}
Void test(int* arr[5])//没门。这是一个指针数组。你必须有一个整数数组指针。
{}
Void test(int(*arr)[5])//Yes。是一个整数数组指针。
{}
Void test(int** arr)//没门。
{}
int main()
{
int arr[3][5]={ 0 };
测试(arr);
返回0;
}
3.一级指针传递参数
#包含stdio.h
Void print(int* pstr,int sz) //用一级指针接收
{
int I=0;
for(I=0;我SZ;我)
{
printf(%d ,*(pstr I));
}
}
无效测试(char* p)
{
}
int main()
{
int arr[7]={ 2,0,2,2,10,0,2 };
int * p=arr
int SZ=sizeof(arr)/sizeof(arr[0]);
打印(p,SZ);//p是一级指针。
char ch= a
测试(ch);//char* class
//char * P1=ch;
//test(P1);
返回0;
}
4.两级指针传递参数
#包含stdio.h
Void test(int** pstr) //二级指针接收
{
printf(num=%d\n ,* * pstr);//a的值
}
int main()
{
int a=10
int * pa=a;//pa是一级指针。
int * * ppa=pa//ppa是二级指针。
测试(PPA);//二级指针传递参数
测试(pa);第一级指针的地址是第二级指针。
int * arr[10]={ 0 };
测试(arr);//还可以传递一个一级指针数组。
//,传递整数指针数组第一个元素的地址,而第一个元素的类型是int*,结果是二级指针传递参数。
返回0;
}
五:函数指针(存储函数地址的指针)
函数名3354取出函数的地址。
注意:数组名!=数组名
函数名==函数名
int (*pf)(int,int)=Add;
#包含stdio.h
int Add(int x,int y)
{
返回x y;
}
int main()
{
printf(%p\n ,Add);
printf(%p\n ,Add);
//地址一样,意思一样,没有区别
int (*pf)(int,int)=Add;//在函数指针中,因为()的优先级高于*,所以需要括号。
int ret=(*pf)(7,5);//通过函数指针调用函数. 1
//int ret=pf(7,5);//2
//int ret=Add(7,5);//3
//1,2,3都一样。*影响不大,是可选的,但只能在函数指针中实现。
//int ret=*pf(7,5);//这个不行。相当于解引用函数的结果12。如果加上*号,必须括起来。
printf(%d\n ,ret);//12
返回0;
}
示例:
#包含stdio.h
无效测试(char* str)
{
}
int main()
{
void(* pt)(char *)=test;//对应函数。
返回0;
}
六:函数指针数组(存储函数指针的数组)
它可以存储多个具有相同参数和相同返回类型的函数地址。
int (*arr[3])(int,int)={ Add,Sub,Mul };
#包含stdio.h
Add (int x,int y)//plus
{
返回x y;
}
Int Sub(int x,int y)//minus
{
返回x-y;
}
Int Mul(int x,int y)//乘法
{
返回x * y;
}
int main()
{
//parr是函数指针数组
int (*parr[3])(int,int)={ Add,Sub,Mul };
返回0;
}
写一个计算器(加、减、乘、除):
(函数指针数组用于传输表格)
#包含stdio.h
Add (int x,int y)//plus
{
返回x y;
}
Int Sub(int x,int y)//minus
{
返回x-y;
}
Int Mul(int x,int y)//乘法
{
返回x * y;
}
Int Div(int x,int y)//除法
{
返回x/y;
}
无效菜单()
{
printf( * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * \ n );
printf(**** 1。加2。sub * * * * \ n’);
printf(**** 3。Mul 4。div * * * * \ n );
printf( * * * * 0 . exit * * * * * * * \ n );
printf( * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * \ n );
}
int main()
{
int input=0;
做{
menu();//菜单
//pfArr是函数指针数组
//传输表
int (*pfArr[5])(int,int)={ NULL,Add,Sub,Mul,Div };//
int x=0;
int y=0;
int ret=0;
Printf(请选择:);
scanf(%d ,输入);
if(输入=1输入=4)
{
Printf(请输入2个数字:);
scanf(%d %d ,x,y);
ret=(*pfArr[input])(x,y);
printf(%d\n ,ret);
}
else if(输入==0)
{
Printf(退出程序\ n );
}
其他
{
Printf(选择错误,重新选择);
}
}while(输入);
返回0;
}
,
七:指向函数指针数组的指针
int(*p)(int,int);//函数指针
int(* p2[4])(int,int);//函数指针数组
int(*(*p3)[4])(int,int);//取出函数指针数组的地址
//p3是指向函数指针数组的指针
补充:int arr[5];
元素类型:去掉数组名和元素个数,剩下的就是—— int。
数组类型:仅删除数组名3354int [5]。
八:回调函数
回调是由函数指针调用的函数。如果你把一个函数的指针作为参数传递给另一个函数,当这个指针被用来调用它所指向的函数时,我们说它是一个回调函数。回调函数不是由函数的实现者直接调用,而是在特定事件或条件发生时由另一方调用,用于响应事件或条件。
回调函数应用示例:
int Add(int x,int y)
{
返回x y;
}
int Sub(int x,int y)
{
返回x-y;
}
整数乘法(整数x,整数y)
{
返回x * y;
}
int Div(int x,int y)
{
返回x/y;
}
无效菜单()
{
printf( * * * * * * * * * * * * * * * * * * * * * * * * * * * \ n );
printf( * * * * * * 1 . add 2。sub * * * * \ n’);
printf( * * * * * * 3 . mul 4。div * * * * \ n );
printf( * * * * * * 0 . exit * * * * \ n );
printf( * * * * * * * * * * * * * * * * * * * * * * * * * * * \ n );
}
//回调函数
int Cald(int (*pf)(int,int))
{
int x=0;
int y=0;
Printf(请输入2个值:);
scanf(%d %d ,a,b);
返回pf(x,y);
}
int main()
{
int input=0;
int x=0;
int y=0;
int ret=0;
做
{
menu();
Printf(请选择:);
scanf(%d ,输入);
开关(输入)
{
案例1:
ret=Cald(Add);//将指针传递给Add函数。
//不直接调用//Add函数,而是通过函数指针调用。
printf(%d\n ,ret);
打破;
案例二:
ret=Cald(Sub);//传递子函数指针。
printf(%d\n ,ret);
打破;
案例三:
ret=Cald(Mul);//传递Mul函数指针。
printf(%d\n ,ret);
打破;
案例4:
ret=Cald(Div);//传递Div函数指针。
printf(%d\n ,ret);
打破;
案例0:
Printf(退出程序\ n );
打破;
默认值:
Printf(选择错误,重新选择\ n );
打破;
}
} while(输入);
}
Qsort库函数(实现快速排序)
(头文件stdlib.h可以加引号)
Void qsort (void* base,//void*可以接收任何类型的地址,所以应用比较广泛;Base存储要排序的数据中第一个对象的地址。
Size_t num,//元素的数量
Size_t size,//一个元素占多少字节?
Int (* compar) (constvoid *,const void *)//用于比较待排序数据中两个元素的函数
);
//
注意:int compare my type (constvoid * a,constvoid * b)
{
if ( *(MyType*)a *(MyType*)b)返回-1;
if ( *(MyType*)a==*(MyType*)b)返回0;
if ( *(MyType*)a *(MyType*)b)返回1;
}
示例:按qsort函数排序
#包含stdio.h
#包含stdlib.h
int compar(常量void* d1,常量void* d2)
{
return *(int *)D1-*(int *)D2;
}
void print_arr(int arr[],int sz)
{
int I=0;
for(I=0;我SZ;我)
{
printf(%d\n ,arr[I]);
}
printf( \ n );
}
int main()
{
int arr[10]={ 9,8,7,6,5,4,3,2,1,0 };
int SZ=sizeof(arr)/sizeof(arr[0]);
qsort(arr,sz,sizeof(arr[0]),compar);//排序
print_arr(arr,SZ);
返回0;
}
九。指针和数组问题分析
//在32位平台上
#包含stdio.h
int main()
{
//在32位平台上,指针的大小都是4字节。
//一维数组
int a[]={ 1,2,3,4 };
printf(%d\n ,sizeof(a));//16计算数组的大小
printf(%d\n ,sizeof(a 0));//4数组第一个元素的地址大小
printf(%d\n ,sizeof(* a));//4第一个元素的大小
printf(%d\n ,sizeof(a 1));//4第二个元素的地址大小
printf(%d\n ,sizeof(a[1]));//4第二个元素的大小
printf(%d\n ,sizeof(a));//4数组的地址
printf(%d\n ,sizeof(* a));//16数组的大小
printf(%d\n ,sizeof(a 1));//4数组后面的空间地址的大小
printf(%d\n ,sizeof(a[0]));//4第一个元素的地址
printf(%d\n ,sizeof(a[0]1));//4第二个元素的地址
//字符数组
1.
char arr[]={ a , b , c , d , e , f };
printf(%d\n ,sizeof(arr));//6数组的大小
printf(%d\n ,sizeof(arr 0));//4第一个字符地址的大小
printf(%d\n ,sizeof(* arr));//1对数组第一个元素的地址的取消引用,即A字符的大小
printf(%d\n ,sizeof(arr[1]));//1
printf(%d\n ,sizeof(arr));//4取出字符数组的地址大小
printf(%d\n ,sizeof(arr 1));//4字符数组后面的地址的大小
printf(%d\n ,sizeof(arr[0]1));//4位字符地址
printf(%d\n ,strlen(arr));//随机值
printf(%d\n ,strlen(arr 0));//随机值
printf(%d\n ,strlen(* arr));//错误
printf(%d\n ,strlen(arr[1]));//错误
printf(%d\n ,strlen(arr));//随机值
printf(%d\n ,strlen(arr 1));//随机值
printf(%d\n ,strlen(arr[0]1));//随机值
2.
char arr[]= abcdef ;//a b c d e f \0
printf(%d\n ,sizeof(arr));//7数组大小
printf(%d\n ,sizeof(arr 0));//4第一个元素地址的大小
printf(%d\n ,sizeof(* arr));//1第一个元素的大小
printf(%d\n ,sizeof(arr[1]));//1第二个元素的大小
printf(%d\n ,sizeof(arr));//4取出整个数组的地址
printf(%d\n ,sizeof(arr 1));//4数组后面的地址
printf(%d\n ,sizeof(arr[0]1));//4第二个元素的地址
printf(%d\n ,strlen(arr));//6
printf(%d\n ,strlen(arr 0));//6
printf(%d\n ,strlen(* arr));//错误
printf(%d\n ,strlen(arr[1]));//err传输字符的ASCLL值,会报错。
printf(%d\n ,strlen(arr));//6
printf(%d\n ,strlen(arr 1));//随机值
printf(%d\n ,strlen(arr[0]1));//5
char * p= abcdef//a b c d e f \0
//将字符串abcdef的第一个字符的地址存储在p变量中
printf(%d\n ,sizeof(p));//4
printf(%d\n ,sizeof(p 1));//4
printf(%d\n ,sizeof(* p));//6
printf(%d\n ,sizeof(p[0]));//4
printf(%d\n ,sizeof(p));//4取P的地址,也就是二级指针,也是4
printf(%d\n ,sizeof(p 1));//4
printf(%d\n ,sizeof(p[0]1));//4
printf(%d\n ,strlen(p));//6
printf(%d\n ,strlen(p 1));//5
printf(%d\n ,strlen(* p));//err a的ASCLL值//为97,会传送到会议进行接入冲突和错误报告。
printf(%d\n ,strlen(p[0]));//错误
printf(%d\n ,strlen(p));//随机值
printf(%d\n ,strlen(p 1));//随机值
printf(%d\n ,strlen(p[0]1));//5
//二维数组
int arr[3][4]={ 0 };
printf(%d\n ,sizeof(arr));//计算整个2D数组的大小,48=12*4
printf(%d\n ,sizeof(arr[0][0]));//4
printf(%d\n ,sizeof(arr[0]));//16=4*4 .arr[0]代表整个第一行,可以理解为第一行的数组名,
Zeof (arr [0])计算第一行的大小。
printf(%d\n ,sizeof(arr[0]1));//arr[0]作为数组名,不单独在sizeof()里面,也不带地址,
//所以在这个例子中,arr[0]是第一行第一个元素的地址
//所以arr[0] 1是第一行第二个元素的地址,大小为4
printf(%d\n ,sizeof(arr 1));//sizeof()内部有运算,arr是二维数组的第一个地址,表示第一行的地址。
//arr 1是第二行的地址,但是地址大小是4个字节。
printf(%d\n ,sizeof(*(arr 1)));//取消对第二行元素的引用,16
printf(%d\n ,sizeof(arr[0]1));//取第一行的地址然后1,就是第二行的地址。尺码是4号
printf(%d\n ,sizeof(* arr));//取消对第一行地址的引用。尺码是16号
printf(%d\n ,sizeof(arr[3]));//虽然我们没有arr[3],但是我们只是计算类型的大小,不会实际访问它。
//所以即使不存在也不会越界访问,大小可以通过类型计算。尺码是16号。
}
转载请联系作者取得转载授权,否则将追究法律责任。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。