一、字符指针变量
字符指针变量(如char* p)的两种赋值方式
①将字符类型地址赋值给字符指针变量
int main()
{
char a = 'w';
char* p = &a;
*p = 'm';
return 0;
}
②将常量字符串赋值给字符指针变量
常量字符串的介绍:用" "引起来的就是常量字符串,常量字符串存放在只读数据区,这块区域的内容是可以用的,但是不能被修改的。
一道关于字符指针变量的面试题
二、数组指针变量
①何为数组指针变量
字符指针变量(如char * p),p中存放的是字符变量的地址,p指向的是字符;整型指针变量(如int * p),p中存放的是整型变量的地址,p指向的是整型。同理,数组指针变量存放的是数组的地址(&数组名),它指向的是数组。
小练习:正确书写数组指针变量
②数组指针变量的使用
但这种写法不常见,通常不会这么写
③区分指针数组与数组指针
三、二维数组传参的本质
①二维数组的数组名
二维数组的每一行可以看做是一个一维数组,即二维数组是由一维数组组成的数组。二维数组的首元素就是它的第一行,因此二维数组的数组名就是数组第一行的地址。
②二维数组中的元素在内存中是连续存放的
③二维数组传参
二维数组传参时,实参写数组名,形参既可以写成数组的形式(此时二维数组的行的大小可以省略),也可以写成指针的形式。
a、形参写成指针的形式
b、形参写成数组的形式
c、补充
arr[i]==*(arr+i)
arr[i][j]==* (*(arr+i)+j) 。
四、函数指针变量
①函数地址的介绍:
数组有地址,变量(如int a)也有地址,那么函数有地址吗?答案是有的。函数的地址是存放在函数指针变量中的。&(函数名)与函数名均表示函数的地址,两者没有区别。 这点与数组不同:&(数组名)表示取出整个数组的地址,数组名表示数组首元素的地址。
② 函数指针变量的创建
函数指针变量是用来存放函数的地址
int Add(int x, int y)
{
return x + y;
}
int main()
{
int(*pa)(int, int) = Add;//或者写成int(*pa)(int x,int y)=Add;
//*表示pa是指针变量(函数指针变量),存放的是函数Add的地址。pa指向的函数的返回类型为int,函数的两个参数也是int类型
//pa的类型是int(*)(int, int)
//*pa表示通过pa中Add的地址,调用Add函数
int ret1 = (*pa)(3, 5);
printf("%d\n", ret1);//8
//一般调用Add函数的方式
int ret2 = Add(3, 5);//这里的Add是函数名,也就是函数的地址。pa中存放的也是函数的地址,故可以将这里的Add换成pa
ret2 = pa(3, 5);
return 0;
}
总结:可以通过函数名(函数的地址)来调用函数,也可以通过对函数指针变量解引用来调用函数。
③
④
⑤
五、typedef关键字
①作用
用于对变量类型(如int、int*)重新命名,将复杂类型的名字简单化。
//比如觉得unsigned int这个类型比较复杂,那么就可以使用typedef将该类型重命名为unit
typedef unsigned int unit;
int main()
{
unsigned int a = 1;//等价于unit a=1;
return 0;
}
②typedef关键字的使用
typedef int* ptr_t;
int main()
{
ptr_t a;//等价于int* a;
return 0;
}
③typedef在重命名数组指针类型和函数指针类型时,稍微有点不同
a.typedef在重命名数组指针类型
typedef int(*parr)[5];//将数组指针类型int(*)[5]重命名为parr
//typedef int(*)[5] parr 这种写法是错误的
int main()
{
int arr[5] = { 0 };
int(*p)[5] = &arr;//数组指针p的类型是int(*)[5]
parr m = &arr;
return 0;
}
b.typedef重命名函数指针类型
typedef int (*pf)(int, int);//将函数指针类型int (*)(int, int)重命名为pf
//typedef int (*)(int, int) pf 这种写法是错误的
int Add(int x, int y)
{
return x + y;
}
int main()
{
int (*p)(int, int) = Add;//p是函数指针变量,它的类型是int (*)(int, int)
pf p2 = Add;
return 0;
}
④
⑤
六、函数指针数组
①函数指针数组是用来存放函数指针或者函数的地址。(函数指针也是用来存放函数的地址,但函数指针只能存放一个函数的地址,而函数指针数组可以存放多个相同类型函数的地址)
②函数指针数组该怎么写呢?
先写出函数指针变量,然后对函数指针变量进行使当的修改,就是函数指针数组。
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()
{
int(*p)(int, int) = Add;//p是函数指针变量,p所指向的函数的返回类型是int,函数的两个参数的类型也是int
int(* p1[4])(int, int) = { Add,Sub,Mul,Div };//p1是函数指针数组的数组名,数组有4个元素,每个元素的类型都是int(*)(int,int)
return 0;
}
③函数指针数组的使用
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()
{
int(*p1)(int, int) = Add;
int(*p2)(int, int) = Sub;
int(*p3)(int, int) = Mul;
int(*p4)(int, int) = Div;
//p1、p2、p3、p4是四个函数指针变量,分别存放四个函数的地址,比较麻烦。
//观察到这四个函数的类型是一样的,因此可以使用函数指针数组来存放四个函数的地址
int(*p[4])(int, int) = {Add,Sub,Mul,Div};//p是函数指针数组的数组名,数组有4个元素,每个元素都是int(*)(int,int)类型
//p[0]=Add,p[1]=Sub,p[2]=Mul,p[3]=Div
for (int i = 0; i < 4; i++)
{
printf("%d\n", p[i](6, 3));
}
return 0;
}
七、转移表
/*设计一个简单的计算器,实现整数的加减乘除*/
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;
}
void menu()
{
printf("***** 1.Add 2.Sub *****\n");
printf("***** 3.Mul 4.Div *****\n");
printf("***** 0.exit *****\n");
}
int main()
{
int input = 0;
int x = 0, y = 0, ret = 0;
do
{
menu();
printf("请选择:");
scanf("%d", &input);
int(*p[5])(int, int) = { 0,Add,Sub,Mul,Div }; //转移表
if (input >= 1 && input <= 4)
{
printf("请输入两个操作数:");
scanf("%d %d", &x, &y);
ret = p[input](x, y);
printf("%d\n", ret);
}
else if (input == 0)
{
printf("退出计算器\n");
}
else
{
printf("输入错误,请重新输入\n");
}
} while (input);
return 0;
}