在函数调用那一篇里已经揭开了值传递的真相:
实参、形参有各自的存储空间(实参也可能只是一个值,而没有存储空间),实参 -> 形参是个值拷贝的过程,在函数调用前完成了这个拷贝过程,此后如果函数中对形参进行修改,实参的值不会跟着变。
但并不是我们就没办法在函数中修改外部变量了,用指针就好了,我们不需要修改指针的值,而只是修改指针指向的内存块:
0重指针(基本类型、结构体)
int add(int a, int b)
{
return a + b;
}
只有这种参数的函数,只需要参数的值,进行计算后返回结果,不需要修改外部变量。
1重指针
void swap(int *a, int *b)
{
int t = *a;
*a = *b;
*b = t;
}
使用场景:
int a=1, b=2;
swap(&a, &b);
函数中使用 1 重指针一般出于两种目的:
- 函数中要修改外部 基本类型 或 结构体 的值。
- 为了节省参数空间。假设函数想要读一个外部的占用空间很大的结构体变量,比如有 4KB 大小,虽然根本没想改它,但是如果用指针接收它的地址,参数只占 4 字节;如果用结构体作为参数,参数要占 4KB 的内存,而且还要进行值拷贝! 用 char* 来接收字符串也可以看做是出于节省空间的目的。
2重指针
C 标准库的头文件 string.h 中提供了一个 strdup 函数:
char *strdup(char *s);
该函数的作用是复制字符串,返回的字符串的存储空间是动态申请的,不是原来字符串的空间。如果你是第 1 次听说有这个函数,不要妄自菲薄,我也是现在下才知道的O(∩_∩)O~
现在不用返回值,用 2 重指针来实现这个函数:
void my_strdup(char **p, char *s)
{
unsigned int len = strlen(s) + 1;
*p = (char *)malloc(len);
memcpy(*p, s, len);
}
使用场景:
char *s = "abc";
char *d = NULL;
my_strdup(&d, s);
从这个例子中可以看出 2 重指针用于需要修改指针的时候,一般是要在函数中为指针动态地申请空间。而这一般可用返回指针来实现,但是如果有多个指针要一并修改,用 2 重指针就要方便很多,因为返回值只有 1 个,而参数的个数在语法上是没有限制的。
strdup 返回的字符串用完后不要忘了 free 哦!
另外,一般没有使用 3 重以上指针作参数的必要。