欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語言函數(shù)指針詳解

 更新時間:2021年09月26日 11:11:15   作者:reindexx  
本文主要介紹 C語言函數(shù)指針的知識,這里整理了詳細的資料及示例代碼以便大家學(xué)習(xí)參考,有需要學(xué)習(xí)此部分知識的朋友可以參考下

Introduction

上一個lab的主要內(nèi)容為__data pointer__(指向數(shù)據(jù)的指針)可能在Linux系統(tǒng)中造成的__segmentation fault__。本次lab將考慮__function pointer__(指向函數(shù)/代碼的指針)可能造成的錯誤:segfault或其他exceptions。

函數(shù)指針 Function Pointers

一個函數(shù)指針可以像函數(shù)一樣被調(diào)用,包括傳遞參數(shù)和獲得返回結(jié)果。函數(shù)指針的一些用途是用于編寫泛型generic函數(shù),有時是一種面向?qū)ο蟮臉邮?,也用于實現(xiàn)回調(diào)。

  • 在函數(shù)中,有物理內(nèi)存地址可以賦值給指針,而一個函數(shù)的函數(shù)名就是一個指針,指向函數(shù)的代碼;
  • 一個函數(shù)的地址就是該函數(shù)的進入點,也是調(diào)用函數(shù)的地址;
  • 函數(shù)的調(diào)用可以通過函數(shù)名,也可以通過指向函數(shù)的指針;
  • 函數(shù)指針還允許將函數(shù)作為變元傳遞給其他函數(shù);
  • 沒有括號和變量列表的函數(shù)名也可以表示函數(shù)的地址(數(shù)組中,不帶下標(biāo)的數(shù)組名表示數(shù)組的首地址)

定義形式

類型 (*指針變量名) (參數(shù)列表);

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

→ p是一個指針,它指向一個函數(shù),該函數(shù)有兩個整型參數(shù),返回類型為int;p首先和*結(jié)合,表明p是一個指針,再與( )結(jié)合,表明它指向的是一個函數(shù)。

調(diào)用函數(shù)指針

(*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;
	//這里定義了一個函數(shù)指針,就可以根據(jù)傳入的flag,靈活地決定其是指向求大數(shù)或求小數(shù)的函數(shù)
	//便于方便靈活地調(diào)用各類函數(shù)
	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 *);
	//將庫函數(shù)strcmp的地址賦值給函數(shù)指針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)調(diào)用strcmp,由cmp指向庫函數(shù)strcmp(),由a和b作調(diào)用strcmp()的參數(shù)。
	//調(diào)用時,與聲明的情況類似,必須在*cmp周圍使用一對括號,使編譯程序正確操作,
	//同時這也是一種良好的編碼風(fēng)格,指示函數(shù)是通過指針調(diào)用的,而不是函數(shù)名。
    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);

前者是返回值是指針的函數(shù);后者是一個指向函數(shù)的指針。

注意 本實驗用到的技巧也將會在JIT編譯器(如,瀏覽器中的JavaScript編譯器)中出現(xiàn),因為它們也是將數(shù)據(jù)轉(zhuǎn)換為代碼,然后再調(diào)用。請注意,試圖執(zhí)行代碼的攻擊可能會使用本實驗室的變體。這個實驗也說明了一個常見的錯誤,可能是不確定的。

Exercise 1:qsort中的函數(shù)指針

  • 為什么 q s o r t ( ) qsort() qsort() 使用函數(shù)指針?
    • q s o r t ( ) qsort() qsort() 是對任何類型的數(shù)組數(shù)據(jù)的通用排序例程(generic sorting routine ),因此,不同的數(shù)據(jù)類型需要不同的比較方法,這是由用戶提供的比較函數(shù) c o m p a r e ( ) compare() compare() 提供的。簡單說就是對數(shù)組進行排序。
    • 聲明:

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

  • 參數(shù):
    • base – 指向要排序的數(shù)組的第一個元素的指針。
    • nitems – 由 base 指向的數(shù)組中元素的個數(shù)。
    • size – 數(shù)組中每個元素的大小,以字節(jié)為單位。
    • compar – 用來比較兩個元素的函數(shù)。如果 compar 返回值< 0,那么第一個參數(shù)p1 所指向元素會被排在第二個p2所指向元素的前面;如果 compar 返回值= 0,那么 p1 所指向元素與 p2 所指向元素的順序不確定;如果 compar 返回值> 0,那么 p1 所指向元素會被排在 p2 所指向元素的后面。
    • 返回值 – 無

代碼

#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); /* a bug as needs deref */
	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); /* bug: same reason as line in string_comp() */
	i1 = atoi(*((char **) p1)); /* correct */
	// i2 = atoi((char *) p2); /* bug: same reason as line in string_comp() */
	i2 = atoi(*((char **) p2)); /* correct */
	// printf("comp(%s,%s)\n", p1, p2); /* bug: for debugging */
	// printf("comp(\"%s\", \"%s\")\n", *(char **) p1, *(char **) p2); /* correct: for debugging */
	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)

說明:當(dāng)s1<s2時,返回為負數(shù) 注意不是-1

當(dāng)s1==s2時,返回值= 0

當(dāng)s1>s2時,返回正數(shù) 注意不是1

即:兩個字符串自左向右逐個字符相比(按ASCII值大小相比較),直到出現(xiàn)不同的字符或遇'\0'為止。如:

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

特別注意:strcmp(const char *s1,const char * s2)這里面只能比較字符串,不能比較數(shù)字等其他形式的參數(shù)。

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};
	/* Try uncommenting out */
	/*
	f = NULL;
	a = f(10);
	printf("0: f(10)=%d f=%p\n\n", a, f);
	*/
	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);
	/* Try swapping the two mmap lines */
	// 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;
}
  • mmap() 函數(shù):
    • 用途:
      • 將一個普通文件映射到內(nèi)存中,通常在需要對文件進行頻繁讀寫時使用,這樣用內(nèi)存讀寫取代I/O讀寫,以獲得較高的性能;
      • 將特殊文件進行匿名內(nèi)存映射,可以為關(guān)聯(lián)進程提供共享內(nèi)存空間;
      • 為無關(guān)聯(lián)的進程提供共享內(nèi)存空間,一般也是將一個普通文件映射到內(nèi)存中。
    • 頭文件:#include <sys/mman.h>
    • 原型:void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offsize);
    • 參數(shù)說明:
      • start:指向欲映射的內(nèi)存起始地址,通常設(shè)為 NULL,代表讓系統(tǒng)自動選定地址,映射成功后返回該地址。
      • length:代表將文件中多大的部分映射到內(nèi)存。
      • prot:映射區(qū)域的保護方式??梢詾橐韵聨追N方式的組合:
        • PROT_EXEC 映射區(qū)域可被執(zhí)行
        • PROT_READ 映射區(qū)域可被讀取
        • PROT_WRITE 映射區(qū)域可被寫入
        • PROT_NONE 映射區(qū)域不能存取
      • flags:影響映射區(qū)域的各種特性。在調(diào)用mmap()時必須要指定MAP_SHARED 或MAP_PRIVATE。
        • MAP_FIXED:如果參數(shù)start所指的地址無法成功建立映射時,則放棄映射,不對地址做修正。通常不鼓勵用此旗標(biāo)。
        • MAP_SHARED:對映射區(qū)域的寫入數(shù)據(jù)會復(fù)制回文件內(nèi),而且允許其他映射該文件的進程共享。
        • MAP_PRIVATE:對映射區(qū)域的寫入操作會產(chǎn)生一個映射文件的復(fù)制,即私人的“寫入時復(fù)制”(copy on write)對此區(qū)域作的任何修改都不會寫回原來的文件內(nèi)容。
        • MAP_ANONYMOUS:建立匿名映射。此時會忽略參數(shù)fd,不涉及文件,而且映射區(qū)域無法和其他進程共享。
        • MAP_DENYWRITE:只允許對映射區(qū)域的寫入操作,其他對文件直接寫入的操作將會被拒絕。
        • MAP_LOCKED:將映射區(qū)域鎖定住,這表示該區(qū)域不會被置換(swap)。

fd:要映射到內(nèi)存中的文件描述符。如果使用匿名內(nèi)存映射時,即flags中設(shè)置了MAP_ANONYMOUS,fd設(shè)為-1。

offset:文件映射的偏移量,通常設(shè)置為0,代表從文件最前方開始對應(yīng),offset必須是分頁大小的整數(shù)倍。

返回值:若映射成功則__返回映射區(qū)的內(nèi)存起始地址__,否則返回MAP_FAILED(-1),錯誤原因存于errno 中。

錯誤代碼:

EBADF 參數(shù)fd 不是有效的文件描述詞

EACCES 存取權(quán)限有誤。如果是M

P_PRIVATE 情況下文件必須可讀,使用MAP_SHARED則要有PROT_WRITE以及該文件要能寫入。

EINVAL 參數(shù)start、length 或offset有一個不合法。

EAGAIN 文件被鎖住,或是有太多內(nèi)存被鎖住。

ENOMEM 內(nèi)存不足。

  • memcpy() 函數(shù):
    • 用途:內(nèi)存復(fù)制。
    • 原型:void *memcpy(void *dest, const void *src, size_t n);
    • 功能:從src的開始位置拷貝n個字節(jié)的數(shù)據(jù)到dest。如果dest存在數(shù)據(jù),將會被覆蓋。
    • 返回值:dest的指針。
    • 頭文件:string.h
  • index() 函數(shù):
    • 用途:找地址。
    • 原型:char * index(const char *s, int c);
    • 功能:用來找出參數(shù)s 字符串中第一個出現(xiàn)的參數(shù)c 地址,然后將該字符出現(xiàn)的地址返回。字符串結(jié)束字符(NULL)也視為字符串一部分。返回值:如果找到指定的字符則返回該字符所在地址,否則返回0。
    • 頭文件:#include <string.h> Exercise 3

代碼:

#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
	/* your code goes here */
	// 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;
}
  • 要求:
    • 加密方法只是讓數(shù)據(jù)XOR亦或整常數(shù)密碼(key,secret)。原始密碼已知,為255。
    • 目標(biāo):從源代碼中移除密碼的依賴性,盡管有人知道源代碼也無法知道密碼(只考慮整數(shù))。
    • 只修改LINE1和LINE2之間的代碼。
  • 限制:
    • 不能使用新函數(shù)或者新包。
    • 需要在運行時,動態(tài)地創(chuàng)建f()所指向的新代碼。(f是隨輸入變化的)
    • 新函數(shù)實現(xiàn)了與encrypt()相同的功能,除了常量來自輸入(讀入為secret)。
    • 加密是密碼的異或,采用(a ^ c)形式,其中c是常數(shù)而不是c變量。
    • 此外,盡管f()是在運行時動態(tài)創(chuàng)建的,但在使用時不應(yīng)該修改。在LINE3測試,即出現(xiàn)segfault。 hint:看看mprotect,它補充了mmap

總結(jié)

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • 淺談C++標(biāo)準(zhǔn)庫

    淺談C++標(biāo)準(zhǔn)庫

    C++標(biāo)準(zhǔn)庫是一組C++模板類,提供了通用的編程數(shù)據(jù)結(jié)構(gòu)和函數(shù),本文簡單講解C++標(biāo)準(zhǔn)庫包含的一些內(nèi)容,可能會對小伙伴的學(xué)習(xí)或工作有一定的幫助,大家一起來看看吧
    2021-08-08
  • OpenCV圖像處理之直方圖比較方法詳解

    OpenCV圖像處理之直方圖比較方法詳解

    直方圖比較是對輸入的兩張圖像進行計算得到直方圖H1與H2,歸一化到相同的尺度空間,然后可以通過計算H1與H2的之間的距離得到兩個直方圖的相似程度,進而比較圖像本身的相似程度。本文將為大家詳細講講直方圖比較的實現(xiàn)方法,需要的可以參考一下
    2022-09-09
  • 詳解如何用c++實現(xiàn)平衡二叉樹

    詳解如何用c++實現(xiàn)平衡二叉樹

    平衡二叉樹(Balanced Binary Tree)又被稱為AVL樹(有別于AVL算法),由前蘇聯(lián)的數(shù)學(xué)家Adelse-Velskil和Landis在1962年提出的高度平衡的二叉樹,根據(jù)科學(xué)家的英文名也稱為AVL樹。本文介紹了它的原理和如何用C++代碼來實現(xiàn)
    2021-06-06
  • C++命名空間域的實現(xiàn)示例

    C++命名空間域的實現(xiàn)示例

    命名空間域就是一個獨立的空間外面不能直接調(diào)用該空間域只能用訪問限定符指定訪問該空間域,本文主要介紹了C++命名空間域的實現(xiàn)示例,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • 基于C++和MFC開發(fā)象棋程序

    基于C++和MFC開發(fā)象棋程序

    這篇文章主要為大家詳細介紹了基于C++和MFC開發(fā)象棋程序,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • Qt中const?QString轉(zhuǎn)換?char?*可能的坑

    Qt中const?QString轉(zhuǎn)換?char?*可能的坑

    本文主要介紹了Qt中const?QString轉(zhuǎn)換?char?*可能的坑,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • C++繼承中的對象構(gòu)造與析構(gòu)和賦值重載詳解

    C++繼承中的對象構(gòu)造與析構(gòu)和賦值重載詳解

    這篇文章主要為大家詳細介紹了C++繼承中的對象構(gòu)造與析構(gòu)和賦值重載,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • C++ vector操作實現(xiàn)

    C++ vector操作實現(xiàn)

    這篇文章主要介紹了C++ vector操作實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • c語言壓縮文件詳細講解

    c語言壓縮文件詳細講解

    這篇文章主要從單文件壓縮、多文件壓縮、多文件異步壓縮講訴了c語言壓縮文件,需要的朋友可以參考下面具體的文章內(nèi)容
    2021-09-09
  • QSS樣式表實現(xiàn)界面換膚功能

    QSS樣式表實現(xiàn)界面換膚功能

    這篇文章主要介紹了QSS樣式表實現(xiàn)界面換膚功能,對QSS樣式表進行簡單介紹,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-10-10

最新評論