我遇到了一个我有几个问题的代码,如果你回答,我将不胜感激
#include <stdio.h>
#include <stdlib.h>
int isOdd(int a) {
return (a % 2 != 0);
}
unsigned int filter(int *arr, unsigned size, int (*pred)(int), int** out) {
unsigned i;
unsigned j;
*out = (int*) malloc(sizeof(int)*size);
for (i = 0, j = 0; i < size; i++) {
if (pred(arr[i])) {
(*out)[j] = arr[i];
j++;
}
}
*out = (int*) realloc(*out, j*sizeof(int));
return j;
}
int main () {
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
unsigned i;
unsigned size;
int *aOdd = NULL;
size = filter(a, 10, isOdd, &aOdd);
for (i = 0; i < size; i++) {
printf("%d ", aOdd[i]);
}
}
问题 #1:为什么需要这种显式转换?
*out = (int*) malloc(sizeof(int)*size);
*out = (int*) realloc(*out, j*sizeof(int));
如果我没记错的话,它们是多余的。
问题 #2:我用感叹号突出显示的行中发生了什么?
unsigned int filter(int *arr, unsigned size, int (*pred)(int), int** out) {
unsigned i;
unsigned j;
*out = (int*) malloc(sizeof(int)*size); /* !!!!!!!!!! */
for (i = 0, j = 0; i < size; i++) {
if (pred(arr[i])) {
(*out)[j] = arr[i]; /* !!!!!!!!!! */
j++;
}
}
*out = (int*) realloc(*out, j*sizeof(int)); /* !!!!!!!!!! */
return j;
}
问题#3:以这种方式实现问题#2中的函数会不会更容易(仅通过指针,而不是通过指向指针的指针)
unsigned int filter(int *arr, unsigned size, int (*pred)(int), int* out) {
unsigned i;
unsigned j;
for (i = 0, j = 0; i < size; i++) {
if (pred(arr[i])) {
*(out + j) = arr[i];
j++;
}
}
return j;
}
问题#2 中的功能和问题#3 中的功能之间是否存在显着差异甚至优势?
C 不需要。对于 C++,它们是必要的,因为 在 C++ 中,不允许从 void* 进行隐式转换。
1) 大小整数的内存分配。
2)将满足谓词的元素复制到新分配的数组中。
3) 截取一块未填充的数据数组
他们给出不同的结果。
对于问题 #2 的变体,内存直接在函数中分配,然后被截断。对于第三个问题选项,这个责任将落在调用者身上。两种方法都有优点和缺点。这完全取决于您如何使用它们。
我之前已经写过这个。当您实现一个结果数组大小事先不知道的函数时,即 只有在函数内部才知道,那么就会出现分配正确数量的内存来存储结果的问题。
用户(即调用代码)一般不能提前分配这块内存,因为他还不知道需要多少内存。在这种情况下,有几个主要策略:
在某些情况下,结果的最大可能大小是预先知道的,可以预先“最大限度地”分配内存,这样的最大分配在有条件的情况下是“合理的”。
这只是你的情况。是的,你的#3 可以很好地使用这种模式。用户只需要至少提供一个大小的输出数组,
size
并记住通常不会使用所有数组。在函数内部分配内存:当它的大小变得已知时立即分配内存,或者随着结果的累积而递增,或者在随后的截断中“最大”,或者其他什么。
这是您的#2 选项。
这种方法的问题在于,这种情况下的内存分配不容易定制。在最简单的情况下,
malloc
就像您的示例一样。也许用户不需要它malloc
?实现 image 和 likeness 中的功能
snprintf
,即 提供“虚拟”传递的可能性,该传递仅计算并返回结果的大小,但尚未生成结果。收到计算的大小后,用户以任何方便的方式分配内存,然后再次调用相同的函数,这次是“真正的”传递,即 在缓冲区中形成结果。
也就是说,您的 #2 和 #3 是解决问题的两种替代方法。这两种方法在他们自己的方式上都是正确的。
除了 Groessmah 的回答之外,我将对第三个问题进行澄清:
您的函数实现错误:首先,没有内存分配 - 您的指针仍然指向
NULL
! 为了在函数中分配内存,你需要一个指向指针的指针,否则你可以分配内存,但是他们会让我们需要的指针指向它——不。其次,如果我们在调用函数之前分配内存,在函数中切割它,同样是行不通的。