Returning an array using C
我对C比较陌生,在处理数组的方法方面需要一些帮助。来自Java编程,我习惯于能够说EDCOX1×0Ω,以便返回数组。但是,我发现使用C时,返回数组时必须使用指针。作为一个新的程序员,我真的完全不理解这一点,即使有很多论坛我都看过。
基本上,我正试图编写一个用C语言返回char数组的方法。我将为该方法(让我们调用它)提供一个数组。它将从上一个数组创建一个新数组,并返回指向它的指针。我只需要一些关于如何开始的帮助,以及如何在指针从数组中发出后读取指针。如有任何解释,我们将不胜感激。
数组返回函数的建议代码格式
1 2 3 4 5 | char *returnArray(char array []){ char returned [10]; //methods to pull values from array, interpret them, and then create new array return &(returned[0]); //is this correct? } |
函数的调用方
1 2 3 4 5 6 7 8 | int main(){ int i=0; char array []={1,0,0,0,0,1,1}; char arrayCount=0; char* returnedArray = returnArray(&arrayCount); ///is this correct? for (i=0; i<10;i++) printf(%d,",", returnedArray[i]); //is this correctly formatted? } |
我还没有测试这个,因为我的C编译器目前不工作,但我想解决这个问题。
不能从C中的函数返回数组。也不能(不应该)这样做:
1 2 3 4 5 | char *returnArray(char array []){ char returned [10]; //methods to pull values from array, interpret them, and then create new array return &(returned[0]); //is this correct? } |
您将需要在函数内部动态分配内存,或者填充调用者提供的预分配缓冲区。
选项1:
在函数内部动态分配内存(调用方负责释放
1 2 3 4 5 6 7 8 9 10 | char *foo(int count) { char *ret = malloc(count); if(!ret) return NULL; for(int i = 0; i < count; ++i) ret[i] = i; return ret; } |
这样称呼它:
1 2 3 4 5 6 7 8 9 |
选项2:
填充调用方提供的预分配缓冲区(调用方分配
1 2 3 4 | void foo(char *buf, int count) { for(int i = 0; i < count; ++i) buf[i] = i; } |
就像这样称呼它:
1 2 3 4 5 6 7 8 9 | int main() { char arr[10] = {0}; foo(arr, 10); // No need to deallocate because we allocated // arr with automatic storage duration. // If we had dynamically allocated it // (i.e. malloc or some variant) then we // would need to call free(arr) } |
C对数组的处理与Java非常不同,因此你必须相应地调整你的思维。C中的数组不是第一类对象(也就是说,数组表达式在大多数上下文中不保留它的"数组性")。在C语言中,"n-element array of EDOCX1"(0)类型的表达式将被隐式转换("decay")为"pointer to EDOCX1"(0)类型的表达式,除非数组表达式是
除此之外,这意味着您不能将数组表达式传递给函数并将其作为数组类型接收;该函数实际上接收指针类型:
1 2 3 4 5 6 7 8 9 10 | void foo(char *a, size_t asize) { // do something with a } int bar(void) { char str[6] ="Hello"; foo(str, sizeof str); } |
在对
如果你真的很感兴趣,你可以阅读丹尼斯·里奇的《C语言的发展》,了解这种治疗的来源。
结果是函数不能返回数组类型,这很好,因为数组表达式也不能作为赋值的目标。
最安全的方法是让调用者定义数组,并将其地址和大小传递给应该写入该数组的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | void returnArray(const char *srcArray, size_t srcSize, char *dstArray, char dstSize) { ... dstArray[i] = some_value_derived_from(srcArray[i]); ... } int main(void) { char src[] ="This is a test"; char dst[sizeof src]; ... returnArray(src, sizeof src, dst, sizeof dst); ... } |
另一种方法是函数动态分配数组并返回指针和大小:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | char *returnArray(const char *srcArray, size_t srcSize, size_t *dstSize) { char *dstArray = malloc(srcSize); if (dstArray) { *dstSize = srcSize; ... } return dstArray; } int main(void) { char src[] ="This is a test"; char *dst; size_t dstSize; dst = returnArray(src, sizeof src, &dstSize); ... free(dst); ... } |
在这种情况下,调用方负责使用
注意,上面代码中的
您可以声明指向
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | char (*returnArray(const char *srcArr, size_t srcSize))[SOME_SIZE] { char (*dstArr)[SOME_SIZE] = malloc(sizeof *dstArr); if (dstArr) { ... (*dstArr)[i] = ...; ... } return dstArr; } int main(void) { char src[] ="This is a test"; char (*dst)[SOME_SIZE]; ... dst = returnArray(src, sizeof src); ... printf("%c", (*dst)[j]); ... } |
上面有几个缺点。首先,C的旧版本希望
这个恶作剧怎么办?
数组H
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | #define IMPORT_ARRAY(TYPE) \ \ struct TYPE##Array { \ TYPE* contents; \ size_t size; \ }; \ \ struct TYPE##Array new_##TYPE##Array() { \ struct TYPE##Array a; \ a.contents = NULL; \ a.size = 0; \ return a; \ } \ \ void array_add(struct TYPE##Array* o, TYPE value) { \ TYPE* a = malloc((o->size + 1) * sizeof(TYPE)); \ TYPE i; \ for(i = 0; i < o->size; ++i) { \ a[i] = o->contents[i]; \ } \ ++(o->size); \ a[o->size - 1] = value; \ free(o->contents); \ o->contents = a; \ } \ void array_destroy(struct TYPE##Array* o) { \ free(o->contents); \ } \ TYPE* array_begin(struct TYPE##Array* o) { \ return o->contents; \ } \ TYPE* array_end(struct TYPE##Array* o) { \ return o->contents + o->size; \ } |
主C
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #include <stdlib.h> #include"array.h" IMPORT_ARRAY(int); struct intArray return_an_array() { struct intArray a; a = new_intArray(); array_add(&a, 1); array_add(&a, 2); array_add(&a, 3); return a; } int main() { struct intArray a; int* it; int* begin; int* end; a = return_an_array(); begin = array_begin(&a); end = array_end(&a); for(it = begin; it != end; ++it) { printf("%d", *it); } array_destroy(&a); getchar(); return 0; } |
我不是说这是针对给定问题的最佳解决方案或首选解决方案。但是,记住函数可以返回结构可能很有用。虽然函数不能返回数组,但数组可以包装在结构中,并且函数可以返回结构,从而携带数组。这适用于固定长度的数组。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { char v[10]; } CHAR_ARRAY; CHAR_ARRAY returnArray(CHAR_ARRAY array_in, int size) { CHAR_ARRAY returned; /* . . . methods to pull values from array, interpret them, and then create new array */ for (int i = 0; i < size; i++ ) returned.v[i] = array_in.v[i] + 1; return returned; // Works! } int main(int argc, char * argv[]) { CHAR_ARRAY array = {1,0,0,0,0,1,1}; char arrayCount = 7; CHAR_ARRAY returnedArray = returnArray(array, arrayCount); for (int i = 0; i < arrayCount; i++) printf("%d,", returnedArray.v[i]); //is this correctly formatted? getchar(); return 0; } |
我邀请对这种技术的优点和缺点的评论。我没费心这么做。
在这种情况下,您将在堆栈上创建一个数组,一旦离开函数范围,该数组将被释放。相反,创建一个动态分配的数组并返回指向它的指针。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | char * returnArray(char *arr, int size) { char *new_arr = malloc(sizeof(char) * size); for(int i = 0; i < size; ++i) { new_arr[i] = arr[i]; } return new_arr; } int main() { char arr[7]= {1,0,0,0,0,1,1}; char *new_arr = returnArray(arr, 7); // don't forget to free the memory after you're done with the array free(new_arr); } |
您可以使用堆内存(通过malloc()调用),就像这里报告的其他答案一样,但必须始终管理内存(每次调用函数时都使用free()函数)。您还可以使用静态数组:
1 2 3 4 5 6 7 8 | char* returnArrayPointer() { static char array[SIZE]; // do something in your array here return array; } |
你不必担心内存管理就可以使用它。
1 2 3 4 5 6 | int main() { char* myArray = returnArrayPointer(); /* use your array here */ /* don't worry to free memory here */ } |
在本例中,必须在数组定义中使用static关键字将数组的生存期设置为application long,这样在返回语句之后就不会销毁它。当然,在整个应用程序生命周期中,您会占用内存中的大小字节,所以要正确地调整大小!
您的方法将返回一个将严重失败的局部堆栈变量。若要返回数组,请在函数外部创建一个数组,将其按地址传递给函数,然后修改它,或者在堆上创建一个数组并返回该变量。两者都可以工作,但第一个不需要任何动态内存分配来使其正常工作。
1 2 3 4 5 6 7 8 9 10 11 12 13 | void returnArray(int size, char *retArray) { // work directly with retArray or memcpy into it from elsewhere like // memcpy(retArray, localArray, size); } #define ARRAY_SIZE 20 int main(void) { char foo[ARRAY_SIZE]; returnArray(ARRAY_SIZE, foo); } |
您可以使用如下代码:
1 2 3 4 5 6 7 |
当您这样做时,应该稍后通过将地址传递给free来释放内存。
还有其他选择。例程可能返回指向某个现有结构的一部分的数组(或数组的一部分)的指针。调用方可能会传递一个数组,而例程只会写入该数组,而不是为新数组分配空间。