文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

C语言函数指针详解

2024-04-02 19:55

关注

Introduction

上一个lab的主要内容为__data pointer__(指向数据的指针)可能在Linux系统中造成的__segmentation fault__。本次lab将考虑__function pointer__(指向函数/代码的指针)可能造成的错误:segfault或其他exceptions。

函数指针 Function Pointers

一个函数指针可以像函数一样被调用,包括传递参数和获得返回结果。函数指针的一些用途是用于编写泛型generic函数,有时是一种面向对象的样式,也用于实现回调。

定义形式

类型 (*指针变量名) (参数列表);

如, int (*p)(int i, int j);

→ p是一个指针,它指向一个函数,该函数有两个整型参数,返回类型为int;p首先和*结合,表明p是一个指针,再与( )结合,表明它指向的是一个函数。

调用函数指针

(*p) (argument)

p (argument)

例子


#include <stdio.h>
#define  GET_MAX 	0
#define  GET_MIN 	1
int get_max(int i,int j)
{
	return i>j?i:j;
}
int get_min(int i,int j)
{
	return i>j?j:i;
}
int compare(int i,int j,int flag)
{
	int ret;
	//这里定义了一个函数指针,就可以根据传入的flag,灵活地决定其是指向求大数或求小数的函数
	//便于方便灵活地调用各类函数
	int (*p)(int,int);
	if(flag == GET_MAX)
		p = get_max;
	else
		p = get_min;
	ret = p(i,j);
	return ret;
}
int main()
{
	int i = 5,j = 10,ret;
	ret = compare(i,j,GET_MAX);
	printf("The MAX is %d\n",ret);
	ret = compare(i,j,GET_MIN);
	printf("The MIN is %d\n",ret);
	return 0 ;
}

#include <stdio.h>
#include <string.h>
void check(char *a,char *b,int (*cmp)(const char *,const char *));
main()
{
    char s1[80],s2[80];
    int (*p)(const char *,const char *);
	//将库函数strcmp的地址赋值给函数指针p
    p=strcmp;
    printf("Enter two strings.\n");
    gets(s1);
    gets(s2);
    check(s1,s2,p);
}
void check(char *a,char *b,int (*cmp)(const char *,const char *))
{
    printf("Testing for equality.\n");
	//表达式(*cmp)(a,b)调用strcmp,由cmp指向库函数strcmp(),由a和b作调用strcmp()的参数。
	//调用时,与声明的情况类似,必须在*cmp周围使用一对括号,使编译程序正确操作,
	//同时这也是一种良好的编码风格,指示函数是通过指针调用的,而不是函数名。
    if((*cmp)(a,b)==0)
        printf("Equal\n");
    else
        printf("Not Equal\n");
}

int *f(int i, int j);

int (*p)(int i, int j);

前者是返回值是指针的函数;后者是一个指向函数的指针。

注意 本实验用到的技巧也将会在JIT编译器(如,浏览器中的JavaScript编译器)中出现,因为它们也是将数据转换为代码,然后再调用。请注意,试图执行代码的攻击可能会使用本实验室的变体。这个实验也说明了一个常见的错误,可能是不确定的。

Exercise 1:qsort中的函数指针

void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))

代码


#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <stdio.h>
// example of qsort using function pointer for comparison function (*compar)()
// see man qsort
char *num[] = {
	"000000001",
	"1", 
	"1000", 
	"  100 ", 
	"1     ", 
};

// compare p1 & p2 as strings
// call with the address of the array element, e.g. &(char *) = char **
int string_comp(const void *p1, const void *p2) 
{
	// be careful that address of element is passed so there is an
	// extra * needed here given that it is already (char *)
	// return strcmp((char *) p1, (char *) p2); 
	return strcmp(*((char **) p1), *((char **) p2));
}
// compare p1 & p2 as integers
int int_comp(const void *p1, const void *p2) 
{
	int i1, i2;
	// i1 = atoi((char *) p1); 
	i1 = atoi(*((char **) p1)); 
	// i2 = atoi((char *) p2); 
	i2 = atoi(*((char **) p2)); 
	// printf("comp(%s,%s)\n", p1, p2); 
	// printf("comp(\"%s\", \"%s\")\n", *(char **) p1, *(char **) p2); 
	if (i1 < i2) return -1;
	else if (i1 == i2) return 0;
	else return 1;
}
void print_array(char *a[], int n)
{
	int i;
	for (i=0; i < n; i++)
		printf("\"%s\" ", a[i]);
}
int main()
{
	printf("Original array\n"); print_array(num, 5); printf("\n");
	qsort(num, 5, sizeof(char *), int_comp);
	printf("sorted array as int\n"); print_array(num, 5); printf("\n");
	qsort(&num, 5, sizeof(char *), string_comp);
	printf("sorted array as string\n"); print_array(num, 5); printf("\n");
	return(0);
}

一般形式:strcmp(字符串1,字符串2)

说明:当s1<s2时,返回为负数 注意不是-1

当s1==s2时,返回值= 0

当s1>s2时,返回正数 注意不是1

即:两个字符串自左向右逐个字符相比(按ASCII值大小相比较),直到出现不同的字符或遇'\0'为止。如:

“A”<“B” “a”>“A” “computer”>“compare”

特别注意:strcmp(const char *s1,const char * s2)这里面只能比较字符串,不能比较数字等其他形式的参数。

Exercise 2:

代码:


#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <sys/mman.h>
#define L (32)
int addnum(int a)
{
	return a+255;
}
int main(int argc, char *argv[], char *envp[])
{
	int a, (*f)(int), *code_buf;
	char *p, data[]={0x0f, 0x0b};
	
	
	f = addnum;
	a = f(10); // LINE1
	printf("1: f(10)=%d f=%p\n\n", a, f);
	code_buf = (int *) mmap(0, 4096, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
	
	// code_buf = (int *) mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
	printf("code_buf %p\n", code_buf);
	memcpy(code_buf, addnum, L);
	f = (int (*)(int)) code_buf;
	a = f(10); // LINE2
	printf("2: f(10)=%d f=%p\n\n", a, f);
	p = index((char *) code_buf, 0xff);
	printf("before *p=%hhx\n", *p);
	*p = 100;
	printf("after *p=%hhx\n", *p);
	a = f(10); // LINE3
	printf("3: f(10)=%d\n\n", a);
	*((char *) code_buf) = 0xc3;
	a = f(10); // LINE4
	printf("4: f(10)=%d\n\n", a);
	memcpy(code_buf, data, 2);
	printf("before last call\n");
	a = f(10); // LINE5
	return 0;
}

fd:要映射到内存中的文件描述符。如果使用匿名内存映射时,即flags中设置了MAP_ANONYMOUS,fd设为-1。

offset:文件映射的偏移量,通常设置为0,代表从文件最前方开始对应,offset必须是分页大小的整数倍。

返回值:若映射成功则__返回映射区的内存起始地址__,否则返回MAP_FAILED(-1),错误原因存于errno 中。

错误代码:

EBADF 参数fd 不是有效的文件描述词

EACCES 存取权限有误。如果是M

P_PRIVATE 情况下文件必须可读,使用MAP_SHARED则要有PROT_WRITE以及该文件要能写入。

EINVAL 参数start、length 或offset有一个不合法。

EAGAIN 文件被锁住,或是有太多内存被锁住。

ENOMEM 内存不足。

代码:


#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <sys/mman.h>
int encrypt(int a) // simple encryption with a (secret) constant
{
	return a ^ 255;
}
int main(int argc, char *argv[], char *envp[])
{
	int (*f)(int);
	int secret, x, y;
	// test encrypt
	f = encrypt;
	printf("1: enter test data\n");
	scanf("%d", &x);
	y = f(x);
	printf("1: test original encrypt(): f(%x)=%x\n", x, y);
	printf("enter new key\n");
	scanf("%d", &secret);
	// create a new function by using encrypt's code-bytes as a template
	// which is similar to encrypt() except that it is xor with the secret
	// key which has been input
	// let f point to the new function created by the code below
	// LINE1
	
	// LINE2
	secret = 255; // erase secret, set it back to the original key 
	// test if it works
	printf("2: value to encrypt\n");
	scanf("%d", &x);
	y = f(x); // should use the input secret key above
	printf("2: f(): f(%x)=%x\n", x, y);
	printf("erased secret %d\n", secret);
	// test if f() is modifiable
	*((int *)f) = 0; // LINE3: must segfault here
	return 0;
}

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注编程网的更多内容!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯