用指针做参数
#include <stdio.h>
void swap(int *a, int* b) {
int t = *a;
*a = *b;
*b = t;
}
int main() {
int a = 3, b = 4;
swap(&a, &b);
printf("%d %d", a, b);
return 0;
}
数组作为参数和返回值
int sum(int a[]) {
int ans = 0;
for (int i = 0; i < sizeof(a); i++) {
ans += a[i]
}
return ans;
}
这个函数是错误的,因为sizeof(a)
无法得到数组的大小。
当把数组作为参数传递给函数时,实际上只有数组的首地址作为指针传递给了函数。换句话说,在函数定义中的int a[]
等价于int *a
。在只有地址信息的情况下,是无法知道数组理由多少个元素的。
正确的做法是加一个参数,即数组元素的个数。
int sum(int a[],int n) {
int ans = 0;
for (int i = 0; i < n; i++) {
ans += a[i];
}
return ans;
}
在上面的代码中,直接把参数a写成了int *a
,暗示a实际上是一个地址。在函数调用时a一定非要传递一个数组,例如:
int main() {
int a[] = {1, 2, 3, 4};
printf("%d\n", sum(a+1, 3));
return 0;
}
总结:
以数组为参数调用函数时,实际上只有数组首地址传递给了函数,需要另加一个参数表示元素个数。除了把数组首地址本身作为实参外,还可以利用指针加减法把其他元素的首地址传递给函数。
一般地,若p是指针,k是正整数,则p+k就是指针p后面第k个元素,p-k就是p前面的第k个元素,而如果p1和p2是类型相同的指针,则p2-p1是从p1到p2的元素个数(不含p2)。
计算左闭右开区间内的元素和(两种写法)
int sum(int *begin, int *end) {
int n = end - begin;
int ans = 0;
for (int i = 0; i < n; i++) {
ans += begin[i];
}
return ans;
}
int sum(int *begin, int *end) {
int ans = 0;
for (int *p = begin; p != end; p++) {
ans += *p;
}
return ans;
}
把函数作为函数的参数
古老的密码
问题描述
给定两个长度相同且不超过100的字符串,判断是否能把其中一个字符串的各个字母重排,然后对26个字母做一个一一映射,使得两个字符串相同。例如JWPUDJSTVP重排后可以得到WJDUPSJPVT,然后把每个字母映射到它的前一个字母(B->A, C->B, …, Z->Y, A->Z),得到VICTORIOUS。输入两个字符串,输出YES或者NO。
C语言的stdlib.h
中有一个叫qsort
的库函数,实现了著名的快速排序算法。它的声明是这样的:
void qsort (void *base, size_t num, size_t size, int (*comparator)(const void *, const void *));
前三个参数不难理解,分别是待排序的数组起始地址、元素个数和每个元素的大小。最后一个参数比较特别,是一个指向函数的指针,该函数应当具有这样的形式:
int cmp(const void *, const void *) {...}
这里得指针是指向常数的“万能”的指针:const void *
,它可以通过强制类型转化变成任意类型的指针。对于本题来说,排序的对象是整型数组,因此要这样写:
int cmp(const void *a, const void *b) {
return *(int *)a - *(int *)b;
}
先把参数a和b转化为真实的类型,然后让cmp函数当a<b
、a=b
、a>b
时分别返回负数、0和正数即可。