C函数和指针

2016-12-14 09:52:07来源:作者:BeginMan's Blog人点击

这节是看《C语言点滴》关于指针的总结笔记:ledger:。

一. 用指针类型作参数形参 利用函数中的指针形参,可以改变传入函数的实参的值。

这个是指针经典用法之一,不累述了。赵岩《C语言点滴》可真是一点一滴,不过指针这块讲解的很不错,比如下面的例子,想改变p的值。

版本1.指针做形参

void f(int *ptr){ ptr = (int *)malloc(sizeof(int)); *ptr = 999;}int main(int argc, char **argv){ int *p, k = 5; p = &k; f(p); printf("%d/n", *p);}

这是一段高危代码,不仅没输出999反而内存泄漏。

ps:其实呢,如果我们在f函数中不动态分配内存的话,这段代码是没问题的。

因为函数调用遵循单向值传递,所以,进入函数时,p 把自身保存的地址传递给ptr,它们同时指向k。在函数f中ptr 指向了malloc 申请的一块内存后,当程序退出, ptr 因为是局部变量,在栈上定义,所以伴随着函数出栈而消失 。这里带来了两个问题,第一,指针p 的指向并没有被改变;第二,malloc 申请的内存由于没有任何指针指向,所以不能利用free 来释放,造成了内存的泄露。”

解决方案: 利用函数返回值 利用指向指针类型的指针 // 1. 利用函数返回值int *f(){ int *ptr = (int *)malloc(sizeof(int)); *ptr = 999; return ptr;}int main(int argc, char **argv){ int *p, k = 5; p = &k; printf("%d/n", *p); p = f(); printf("%d/n", *p); free(p); // 避免内存泄漏}// 2. 利用指向指针类型的指针void f(int **ptr){ *ptr = (int *)malloc(sizeof(int)); **ptr = 999;}int main(int argc, char **argv){ int *p, k = 5; p = &k; printf("%d/n", *p); f(&p); // 传入的是指针变量的地址 printf("%d/n", *p); free(p); // 避免内存泄漏} 二. 函数返回指针类型

常见错误:

char* func(int i){ char str[100]; // 大小不确定 return str; // error }

函数中数组str定义在栈上,所以str 会随着函数的结束而消失,虽然通过函数返回了一个指针,但是指向一个消失变量的指针还有什么意义呢?

不完美的解决方案:

利用malloc 函数从堆申请出一片内存,这块内存不会伴随着函数的退出而消失。所以使用完这个函数后,我们必须调用free 函数来释放内存。

char* func(int i){ char *str = (char *) malloc(100); return str;}

这个解决方案之所以不完美是因为我们还要free来释放内存.

更好的接口定义:

允许函数传入一个地址。当使用这个函数时,你可以通过指针p 传入一个数组,或者传入一个malloc 函数分配的内存。如果你使用malloc 函数分配的内存,你应该有责任使用free 来释放这片内存。另外,这个函数还把传入的地址返回,这样这个函数就可以直接用在表达式中

char* func(int i, char *p) { // 具体实现... return p;}char a[100]; // 或 char *a = malloc(n);printf("%s", func(1, a)); 三. 函数指针 指向一个函数,函数指针最常见的一个用处就是:”回调函数”

函数指针的声明和数组指针有点类似:

int (*p)[3]; // 数组指针,指向的是一个数组int (pf)(); // 函数指针,指向的就是一个函数,这个函数返回一个整数pf=&func; // 取地址运算符 来让函数指针pf 指向一个特定的函数func// 用如下方式皆可调用func这个函数pf();(*pf)();

如下实例:

int f(int i, int j){ return i+j;}int main(int argc, char **argv){ int (*fp)(); fp = &f; int m = (*fp)(1, 2); int n = fp(1, 2); printf("%d, %d", m, n);}

下面实现一个支持多种类型的冒泡排序算法:

#include <stdio.h>#include <stdlib.h>/* * 第一个参数为要排序的数组 * 第二个参数为数组内的数量 * 第三个参数为数组元素类型所占的空间字节大小 * 第四个参数为函数指针 */void sort(void *data, int n, int type_size, int (*ptr)(const void *, const void *)){ int i, j; void *temp = malloc(type_size); void *addr_1, *addr_2; for (i = 0; i < n - 1; ++i) { for (j = i+1; j < n; ++j) { addr_1 = data + i * type_size; addr_2 = data + j * type_size; if (ptr(addr_1, addr_2) > 0) { memcpy(temp, addr_1, type_size); memcpy(addr_1, addr_2, type_size); memcpy(addr_2, temp, type_size); } } } free(temp);}/* * 浮点数比较程序 */int comp_double(const void *a, const void *b){ if (*(double *)a - *(double *)b > 0) { return 1; } else if (*(double *)a - *(double *)b < 0.001) { return 0; } return -1;}/* * 整数比较 */int comp_int(const void *a, const void *b){ return *(int *)a > *(int *)b;}int main(int argc, char **argv){ double n[] = {19.23, 0.32, 88.32, 20.31, 2.193}; sort(n, 5, sizeof(double), ∁_double); for (int i = 0; i <5; ++i) { printf("%10.3f", n[i]); } printf("/n"); int m[] = {2, 3, 1, 8, 3, 4}; sort(m, 6, sizeof(int), ∁_int); for (int i = 0; i <5; ++i) { printf("%10d", m[i]); } printf("/n");}

标准库中有qsort 函数,采用快速排序算法,比冒泡排序效率要高。qsort 函数采用的也是这种基于回调函数的方法。

(完)~

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台