最近在看《深入理解C指针这本书》,为了不让自己忘记,就把里面的知识点记录了下来。后面的一系列文章都是这本书的笔记。
目录
指针与函数_返回指针
在下面的函数中,我们定义一个函数,为其传递一个整数数组的长度和一个值来初始化每个元素。函数为整数数组分配内存,用传入的值进行初始化,然后返回数组地址。
int *allocateArray(int size, int value)
{
int *arr = (int *)malloc(size * sizeof(int));
for (int i = 0; i < size; i++)
{
arr[i] = value;
}
return arr;
}
int main()
{
int *vector = allocateArray(5, 45);
for (int i = 0; i < 5; i++)
{
printf("%d\n", vector[i]);
}
free(vector);//记得释放内存,以免造成内存泄漏
}
下图说明了这个函数的内存分配。左图显示return语句执行前的程序状态,右图显示函数返回后的程序状态。vector变量指向了函数内分配的内存的地址。当函数终止时,arr变量也会消失,但是指针所引用的内存还在,这部分内存最终需要释放。
函数返回指针可能存在的几个问题:
返回未初始化的指针;
返回指向无效地址的指针;
返回局部变量的指针;
返回指针但是没有释放内存。
指针与函数_返回局部数据指针问题
接上一个,这次我们不为数组分配动态内存,而是用了一个局部数组。
//局部数据指针
int *allocateArray(int size, int value)
{
int arr[5];
for (int i = 0; i < size; i++)
{
arr[i] = value;
}
return arr;
}
int main()
{
int *vector = allocateArray(5, 45);
for (int i = 0; i < 5; i++)
{
printf("%d\n", vector[i]);
}
free(vector);
}
程序运行会有问题,运行结果如下。
函数调用前后,内存分配图如下:
指针与函数_函数指针
声明函数指针:void (*fprt)(int );
声明函数指针类型:typedef void (*fptr) (int );
使用函数指针类型来声明函数指针变量:fptr fptr1;
int* (*f6)();//声明了一个函数指针,它指向的函数的返回值是一个指针
使用函数指针:
#include<stdio.h>
int square(int num)
{
return num*num;
}
int main()
{
int n = 5;
int(*fptr1)(int);
fptr1 = square;
printf("%d square is %d\n", n, fptr1(n));
}
结果如下:
我们也可以向下面那样用取地址操作符对函数名进行操作,但是没有必要这么做。编译器会忽略去地址操作符。
fptr1=□
注:在调用函数的时候,也可以(*fptr1(n)),(*square(n));不过感觉没有必要,多此一举。知道可以这样就好。
#include<stdio.h>
typedef int(*fun) (int, int);
int add(int a, int b)
{
return a + b;
}
int substract(int a, int b)
{
return a - b;
}
int calculate(fun fun1, int a, int b)
{
printf("%d\n",fun1(a, b));
}
int main(void)
{
//函数指针做参数
calculate(substract, 1, 2);
fun fun2 = add;//直接这样用,不要加&,*啥的,知道就可以了。
fun fun3 = &add;
printf("%d\n", fun2(1, 2));
printf("%d\n", (*fun2)(1, 2));//这里*fun2得加括号,优先级问题。
printf("%d\n", fun3(1, 2));
printf("%d\n", (*fun3)(1, 2));
printf("%d\n", (*add)(1, 2));
int(*funfun) (int, int);
funfun = substract;
printf("%d\n", funfun(1, 2));
return 0;
}
函数指针常量:函数名
函数指针变量
函数指针类型
指针与函数_返回函数指针
返回函数指针,其实就是返回一个函数。返回值为一个函数名就可以了。
#include<stdio.h>
int add(int num1, int num2)
{
return num1 + num2;
}
int subtract(int num1, int num2)
{
return num1 - num2;
}
typedef int(*fptrOperation)(int, int);
fptrOperation select(char opcode)//select函数根据输入的字符来判断返回add或者subtract
{
switch (opcode)
{
case '+':return add;
case '-':return subtract;
}
}
int evaluate(char opcode, int num1, int num2)
{
fptrOperation operation = select(opcode);
return operation(num1 , num2);
}
int main(void)
{
printf("%d\n", evaluate('+', 5, 6));
printf("%d\n", evaluate('-', 5, 6));
return 0;
}
运行结果如下:
指针与函数_函数指针作参数
//在一个函数中调用另一个函数
//compute函数根据函数指针参数来决定是求和还是做差
#include<stdio.h>
int add(int num1, int num2)
{
return num1 + num2;
}
int subtract(int num1, int num2)
{
return num1 - num2;
}
typedef int(*fptroperation)(int, int);
int compute(fptroperation operation, int num1, int num2)
{
return operation(num1, num2);
}
int main()
{
int num1 = 5, num2 = 6;
printf("%d\n", compute(add, num1, num2));
printf("%d\n", compute(subtract, num1, num2));
return 0;
}
运行结果如下:
指针与函数_函数指针转换
一、函数指针变量指向其他格式的函数
#include<stdio.h>
int add(int num1, int num2)
{
return num1 + num2;
}
typedef int(*fptr1)(int);
typedef int(*fptr2)(int, int);
int main()
{
fptr2 fptr_2 = add;
fptr1 fptr_1 = add;
printf("%d\n", fptr_1(1, 2));//这样居然没报错,只提示一个警告。
printf("%d\n", fptr_2(5, 6));
return 0;
}
上面没有报错,只提示了两个警告:warning C4020: “fptr_1”: 实参太多;warning C4113: “int (__cdecl *)(int,int)”和“fptr1”的参数列表不同。
程序还是运行了出来
二、函数指针与数据指针
#include<stdio.h>
int add(int num1, int num2)
{
return num1 + num2;
}
typedef int(*fptr)(int, int);
int main()
{
int a = 10;
int *p = &a;
fptr fptr1 = add;
fptr1 = p;
printf("%d\n", *fptr1);
printf("%d\n", *(int *)fptr1);
p = add;
//printf("%d\n", p(5, 6));//这里不强制类型转换的话会报错
printf("%d\n", ((fptr)p)(5, 6));
return 0;
}
程序运行结果:
无法保证函数指针和数据指针相互转化后正常工作。
总结:自己用函数指针的时候还是规规矩矩的来把。
指针与函数_比较函数指针
我们可以用相等和不等操作符来比较函数指针,来判断函数指针是否指向了某一个函数。
//比较函数指针,来判断函数指针是否指向了那个函数
#include<stdio.h>
int add(int num1, int num2)
{
return num1 + num2;
}
typedef int(*fptr)(int, int);
int main()
{
fptr fptr1 = add;
if (fptr1 == add)
{
printf("fptr1 points to add.\n");
}
else
{
printf("fptr1 doesn't point to add.\n");
}
return 0;
}