S1E30:指针函数和函数指针 课后作业

测试题:
0. 函数名在表达式中应该如何被解读?

答:为函数的地址

答案:函数名可以在表达式中被解读成“指向该函数的指针”。


LU,0-3_4Q1JzEd=Z)S[*
1. 函数指针和指针函数有什么区别?

答:函数指针:为一个指向函数的指针   指针函数:函数的返回值为一个指针

答案:函数指针是一个指向函数的指针;指针函数是一个返回指针变量的函数。


;X!oSFD*qaYgO@5>NP7ZsU`V]AkLyh
2. 一个函数能否有时候返回整型指针,有时候返回字符指针?

答:可以,蒙的

答案:能,定义一个 void * 类型的指针函数。

比如下面代码:

#include <stdio.h>

void *func(int n, int *ptr, char *str);

void *func(int n, int *ptr, char *str)
{
        if (n > 0)
        {
                return ptr;
        }
        else
        {
                return str;
        }
}

int main(void)
{
        int num = 520;
        char *str = "FishC";

        printf("%d\n", * (int *) (func(1, &num, str)));
        printf("%s\n", (char *) func(-1, &num, str));

        return 0;
}

程序实现如下:

注:-Wall 选项表示让 GCC 生成所有警告信息(最严格),但编译器仍然对于我们的行为无动于衷。

3. 请问下面代码存在什么问题?

#include <stdio.h>

int *func(int n);

int *func(int n)
{
        n++;

        return &n;
}

int main(void)
{
        printf("%d\n", *func(520));

        return 0;
}

答:取址符不能取左值(错误

答案:上面代码试图返回形参的地址,这跟返回局部变量的地址一样是错误的!因为形参和局部变量在程序运行的时候都是存放在栈中,函数一旦结束调用,栈的空间即释放(虽然不是立刻释放,但其内存空间随时会被覆盖),所以大家跟我一起大声读出来:不要返回局部变量的指针

4. 有一个指针函数 a,它的返回一个字符串,它有两个参数 b 和 c,其中 b 是一个字符串,c 是一个指向参数为 int 类型,返回值为 void 类型的函数指针。那么……请写出指针函数 a 的声明。

答:char  (*a) (char * b, int  (*c) (int) );

答案:char *a ( char *b, void (*c) (int) );

5. 请解释下面代码中 func 是个什么东东?

void ( *func ( int, void (*) (int) ) ) (int)

答:指针函数返回的指针,作为函数指针的类型(错误

答案:解这种题,除非你对指针特别熟练,否则请从最里边的小括号开始分析。

  • void (*) (int) 是一个函数指针(没有名字),它指向一个参数为 int 类型,返回值为 void 类型的函数
  • func ( int, void(*) (int) ) 可以写成 func (int, 函数指针) 的形式
  • func 也是一个函数,它有两个参数,返回值是一个函数指针 void (*) (int)

总结:func 是一个返回值为函数指针(指向一个参数为 int 类型,返回值为 void 类型的函数)的函数,func 有两个参数,第一个参数是 int 类型,第二个参数为函数指针(指向一个参数为 int 类型,返回值为 void 类型的函数)。
注:这道题除了考察你对C语言指针的理解程度之外,几乎没有任何作用,在实际开发中,请不要写这样的代码折腾你的同事……

动动手:
0. 编写一个函数,接收用户输入的字符串,并对该字符串进行 MD5 加密后返回密文。
那……什么是 MD5?MD5 怎么加密?


要求:封装一个 MD5 函数。第一个参数是目标字符串,用于接收运算后的 MD5 值;第二参数是源字符串,即用户输入的明文密码。
程序实现如下:

答:复制答案,运行不了

#include <stdio.h>
#include <string.h>
#include "md5.h"

void md5(unsigned char *dest,unsigned char *src);

void md5(unsigned char *dest,unsigned char *src)
{
	int i;
	
	MD5_CTX md5;
	
	//初始化
	MD5Init(&md5);
	
	MD5Update(&md5,src,strlen((char*)src));
	
	MD5Final(&md5,dest); 
	
	
}

int main(void)
{
	int i;
	unsigned char src[128];
	unsigned char dest[16];
	
	printf("请输入密码:");
	
	md5(dest,src);
	
	printf("加密后的密码是:");
	
	for(i=0;i<16;i++)
	{
		printf("%02x",dest[i]);	
	} 
	 putchar('\n');
	 
	 return 0;

}

答案:

#include <stdio.h>
#include <string.h>
#include "md5.h"

void md5(unsigned char *dest, unsigned char *src);

void md5(unsigned char *dest, unsigned char *src)
{
        int i;

        MD5_CTX md5;

        // 初始化
        MD5Init(&md5);
        // 传入明文字符串及其长度
        MD5Update(&md5, src, strlen((char *)src));
        // 得到加密后的字符串
        MD5Final(&md5, dest);
}

int main(void)
{
        int i;
        unsigned char src[128];
        unsigned char dest[16];

        printf("请输入密码:");
        scanf("%s", src);

        printf("你输入的密码是:%s\n", src);

        md5(dest, src);

        printf("加密后的密码是:");
        for (i = 0; i < 16; i++)
        {
                printf("%02x", dest[i]);
        }
        putchar('\n');

        return 0;
}

1. MD5 虽然没法逆向,但随着计算机运算能力的提升以及硬盘成本的降低,人们想到了将所有常见的单词组合的 MD5 结果建立数据库以供查询,比较出名的有 md5在线解密破解,md5解密加密 平台,该平台就保存着 24 万亿条加密信息……n

提示1:上一题 MD5 计算出来的值并不是以字节的形式存放(所以我们是 %02x 的形式打印的,记得吗?),所以要将中间 16 位提取出来并加到原始密码的后边,需要大家花点心思琢磨。
提示2:snprintf 函数(中文文档 -> 传送门)或许可以助你一臂之力!
程序实现如下:

答:上一题我都答不出来,这题更是不会

答案:

#include <stdio.h>
#include <string.h>
#include "md5.h"

#define LIMIT 128

void md5(unsigned char *dest, unsigned char *src);
void salt(unsigned char *mix, unsigned char *src);

void md5(unsigned char *dest, unsigned char *src)
{
        int i;

        MD5_CTX md5;

        // 初始化
        MD5Init(&md5);
        // 传入明文字符串及其长度
        MD5Update(&md5, src, strlen((char *)src));
        // 得到加密后的字符串
        MD5Final(&md5, dest);
}

void salt(unsigned char *mix, unsigned char *src)
{
        unsigned char temp1[16]; // 存储原始数据第一次计算MD5的值
        unsigned char temp2[16]; // 存储temp1中间16位为字符串
        int i, j, length;

        md5(temp1, src);

        for (i = 4, j = 0; i < 12; i++, j++)
        {
                snprintf(temp2 + 2*j, 16, "%02x", temp1[i]);
        }

        length = strlen(src);

        strncpy(mix, src, length);
        strncat(mix, temp2, 16);

        mix[length + 16 + 1] = '\0';
}

int main(void)
{
        int i;
        unsigned char src[LIMIT];
        unsigned char mix[LIMIT + 16];
        unsigned char dest[16];

        printf("请输入密码:");
        scanf("%s", src);

        printf("你输入的密码是:%s\n", src);

        salt(mix, src);
        printf("加盐后的密码是:%s\n", mix);

        md5(dest, mix);
        printf("加密后的密码是:");
        for (i = 0; i < 16; i++)
        {
                printf("%02x", dest[i]);
        }
        putchar('\n');

        return 0;
}

2. 请编写一个程序,要求用户输入两个数,分别计算它们加减乘除的结果。
请确保你的代码符合下面要求:2

  • 加减乘除分别由四个函数实现:add、sub、mul 和 divi
  • 定义一个函数指针数组指向上面四个函数
  • 只能通过函数指针的形式访问上面四个函数
  • 需要支持浮点数,注意除数不能为 0

程序实现如下:

答:很有代表性的一道题,我的方法也可以

#include <stdio.h>

float add(float num1,float num2)
{
	return (num1+num2);
}

float sub(float num1,float num2)
{
	return (num1-num2);
}

float mul(float num1,float num2)
{
	return (num1 * num2);
}

float divi(float num1,float num2)
{
	if(num2 == 0){
		return 0;
	}
	else{
		return (num1/num2);
	}	
}

float calc(float (*fp)(float, float), float num1, float num2) 
{
	return (*fp)(num1,num2);
}


int main()
{
	float num1,num2;
	printf("请输入两个:");
	scanf("%f  %f",&num1,&num2); 
	printf("对这两个数加减乘除后的结果是:%.2f  %.2f  %.2f  %.2f",
	calc(add,num1,num2),calc(sub,num1,num2),calc(mul,num1,num2),calc(divi,num1,num2)); 
}

答案:
 

#include <stdio.h>
#include <stdlib.h>

#define EPSINON 0.000001 // 定义允许的误差

double add(double x, double y);
double sub(double x, double y);
double mul(double x, double y);
double divi(double x, double y);

double add(double x, double y)
{
        return x + y;
}

double sub(double x, double y)
{
        return x - y;
}

double mul(double x, double y)
{
        return x * y;
}

double divi(double x, double y)
{
        // 不要对浮点数进行==或!=比较,因为IEEE浮点数是一个近似值
        if (y >= -EPSINON && y <= EPSINON)
        {
                printf("除数不能为0\n");
                // 如果除数为0,调用exit()函数直接退出程序
                exit(1);
        }
        else
        {
                return x / y;
        }
}

int main(void)
{
        int i;
        double x, y, result;
        double (*func_table[4])(double, double) = {add, sub, mul, divi};

        printf("请输入两个数:");
        scanf("%lf %lf", &x, &y);

        printf("对这两个数进行加减乘除后的结果是:");
        for (i = 0; i < 4; i++)
        {
                result = (*func_table[i])(x, y);
                printf("%.2f ", result);
        }
        putchar('\n');

        return 0;
}

  • 40
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值