目录
1.字符指针
#include<stdio.h>
int main (){
char *ps="hello world";
printf("%c",*ps);
return 0;
//输出:h
//本质上是把"hello world"这个字符串的首字符
//的地址存储在了ps中
}
#include<stdio.h>
int main (){
char *ps="hello world";
printf("%s",ps);
return 0;
//输出:hello world
//给出字符串首个元素的地址,就可以输出这个字符串
}
字符串数组和字符串指针的区别
int main ()
{
char str1 [] = "hello bit.";
char str2 [] = "hello bit.";
char* str3= "hello bit.";
char* str4="hello bit.";
if (str1==str2)
printf ("strl and str2 are same\n");
else{printf ("strl 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;
/*
strl and str2 are not same
str3 and str4 are same
*/
}
int main ()
{
char str1 [] = "hello bit.";
char str2 [] = "hello bit.";
char* str3= "hello bit.";
char* str4="hello bit.";
*str3='w';
printf("%s",str3) ;
/*
没有输出,因为''hello world''是一个常量字符串!
*/
}
2.指针数组
3.数组指针
3-1.一维数组指针
3-1-1.如何取出整个数组的地址
#include<stdio.h>
int main()
{
int arr[10] ={1,2,3,4,5};
int(*parr)[10]=&arr;
//取出的是数组的地址
//parr 就是一个数组指针-其中存放的是数组的地址
arr;
//arr-数组名是首元素的地址-arr[0]的地址
return 0;
}
3-1-2.如何用指针遍历一维数组
#include<stdio.h>
int main()
{ //遍历arr数组
int arr[10] ={1,2,3,4,5,6,7,8,9,10};
int (*p)[10]=&arr;
int i;
for(i=0;i<10;i++){
printf("%d\n",*(*p+i));
}
return 0;
}
注意:为什么不写成printf("%d",*(p+1)呢
原因在于指针p指向的是数组arr 所以p+1就是p加上整个arr数组的长度
(*p)才是数组首元素的地址
注意:数组名是数组首元素的地址,但是有2个例外:
1.sizeof(数组名)-数组名表示整个组,计算的是整个数组大小,单位是字节
2.&数组名-数组名表示整个数组,取出的是整个数组的地址
3-2.二维数组指针
3-2-1. 如何用指针遍历二维数组
#include<stdio.h>
void bianli(int (*p)[4],int n,int m);
int main(){
int arr[3][4]={{0,1,2,3},{4,5,6,7},{8,9,10,11}};
bianli(arr,3,4);
return 0;
}
void bianli(int (*p)[4],int n,int m){
int i,j;
for(i=0;i<n;i++){
for(j=0;j<m;j++){
printf("%2d ",*(*(p+i)+j));
}
printf("\n");
}
}
//输出 0 1 2 3
// 4 5 6 7
// 8 9 10 11
3-2-2.遍历时的注意事项
遍历二维数组应该写成*(*(p+i)+j)
*(p+1)表示取地址上的数据,也就是整个第i行的数据。是多个数据。
*(p+1)单独使用时表示的是第 i 行数据,放在表达式中会被转换为第 i 行数据的首地址,也就是第 i 行第 0 个元素的地址,
因为使用整行数据没有实际的含义,编译器遇到这种情况都会转换为指向该行第 0 个元素的指针;就像一维数组的名字,在定义时或者和 sizeof、& 一起使用时才表示整个数组,出现在表达式中就会被转换为指向数组第 0 个元素的指针。
4.指针传参
4-1. 一级指针传参
4-2. 二级指针传参
注:&a只是一个地址的值 只有把这个值放到一个变量里才会有地址!
5.函数指针
注意:Add与&Add是等价的
Add可以直接赋给pf
Add也等价于pf
#include<stdio.h>
int Add(int x,int y);
int main()
{ // pf就是一个函数指针变量
int (*pf)(int,int)=&Add;
// int (*pf)(int,int)=Add; Add与&Add是等价的!!!
// Add === pf 等价的
int ret= (*pf) (3,5);//输出8
int ret=pf (3, 5) ;//输出8
int ret= Add (3, 5) ;//输出8
}
int Add(int x,int y){
return x+y;
}
5-2. 理解两个有趣的代码(来自c陷阱和缺陷)
5-2-1.
(*(void)(*)()0)();
调用地址为0处的函数
该函数无参 返回类型是void
1.void(*)()是函数指针类型
2.(void(*)())0对0进行强制类型转化,被解释为一个函数地址
3.*(void(*)())0对0地址进行了解引用操作
4.(*(void(*)())0)() 调用函数
5-2-2
void(*signal(int,void(*)(int)))(int);
1.signal先和()结合,说明signal是一个函数
2.signal的第一个参数类型是int,第二个参数类型是函数指针
这个函数指针指向一个参数类型为int,返回类型为void的函数
3.signal函数的返回类型也是一个函数指针
为了更好理解,可以把这个代码解释为
typedef 对类型进行重定义
typedef void(*pfun_t)(int);//把void(*)()改写成为pfun_t
pfun_t signal(int,pfun_t)
6.函数指针数组
6-1.应用part
6-1-1.计算机(加减乘除) 原始代码呈现
#include<stdio.h>
int add(int x,int y){
return x+y;
}
int sub(int x,int y){
return x-y;
}
int mul(int x,int y){
return x*y;
}
int div(int x,int y){
return x/y;
}
int main(){
printf("1:add\n");
printf("2:sub\n");
printf("3:mul\n");
printf("4:div\n");
printf("请输入你要进行的计算:");
int input,x,y;
scanf("%d",&input);
switch(input){
int ret;
case 1:
printf("选择两个操作数:");
scanf("%d %d",&x,&y);
ret=add(x,y);
printf("%d",ret);
case 2:
printf("选择两个操作数:");
scanf("%d %d",&x,&y);
ret=sub(x,y);
printf("%d",ret);
case 3:
printf("选择两个操作数:");
scanf("%d %d",&x,&y);
ret=mul(x,y);
printf("%d",ret);
case 4:
printf("选择两个操作数:");
scanf("%d %d",&x,&y);
ret=div(x,y);
printf("%d",ret);
}
return 0;
}
一个直球的代码 重复部分多 比较冗长
6-1-2.利用函数指针数组简化
#include<stdio.h>
int add(int x,int y){
return x+y;
}
int sub(int x,int y){
return x-y;
}
int mul(int x,int y){
return x*y;
}
int div(int x,int y){
return x/y;
}
int main(){
printf("1:add\n");
printf("2:sub\n");
printf("3:mul\n");
printf("4:div\n");
printf("请输入你要进行的计算:");
int input,x,y,ret;
scanf("%d",&input);
printf("选择两个操作数:");
scanf("%d %d",&x,&y);
int (*arr[5])(int,int)={0,add,sub,mul,div};//重要步骤!!
ret=arr[input](x,y);//调用!!
printf("%d",ret);
return 0;
}
函数指针数组相当于一个跳板,使我们可以调用出所需的函数(将函数的地址放在数组中)
6-2-2.利用回调函数来简化代码
#include<stdio.h>
int add(int x,int y){
return x+y;
}
int sub(int x,int y){
return x-y;
}
int mul(int x,int y){
return x*y;
}
int div(int x,int y){
return x/y;
}
int calc(int (*p)(int,int)){
int x,y,ret;
printf("选择两个操作数:");
scanf("%d %d",&x,&y);
ret=p(x,y);
return ret;
}
int main(){
printf("1:add\n");
printf("2:sub\n");
printf("3:mul\n");
printf("4:div\n");
printf("请输入你要进行的计算:");
int input,x,y;
scanf("%d",&input);
switch(input){
int ret;
case 1:
ret=calc(add);
printf("%d",ret);
case 2:
ret=calc(sub);
printf("%d",ret);
case 3:
ret=calc(mul);
printf("%d",ret);
case 4:
ret=calc(div);
printf("%d",ret);
}
return 0;
}