使用C返回一个数组
我对C来说比较新,我需要一些处理数组的方法。 来自Java编程,我习惯于能够说int [] method()
为了返回一个数组。 不过,我发现用C语言你必须在返回数组时使用指针。 作为一个新的程序员,我真的不明白这一点,即使我看过很多论坛。
基本上,我试图编写一个返回在C中的字符数组的方法。我将提供一个数组的方法(让我们调用它的returnArray)。 它将从前面的数组中创build一个新的数组,并返回一个指向它的指针。 我只是需要一些帮助,如何获得这个开始,以及如何读取指针,一旦它被发送出arrays。 任何帮助解释这一点表示赞赏。
数组返回函数的build议代码格式
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? }
函数的调用者
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? }
我还没有testing过,因为我的C编译器目前不工作,但我想知道这一点
你不能从C中的函数返回数组。你也不能(不应该)这样做:
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? }
returned
会创build自动存储持续时间,一旦离开其声明范围,即函数返回时,对它的引用将变为无效。
您将需要dynamic分配函数内部的内存或填充调用者提供的预分配的缓冲区。
选项1:
dynamic分配函数内部的内存(调用者负责释放ret
)
char *foo(int count) { char *ret = malloc(count); if(!ret) return NULL; for(int i = 0; i < count; ++i) ret[i] = i; return ret; }
像这样调用它:
int main() { char *p = foo(10); if(p) { // do stuff with p free(p); } return 0; }
选项2:
填充调用者提供的预先分配的缓冲区(调用者分配buf
并传递给函数)
void foo(char *buf, int count) { for(int i = 0; i < count; ++i) buf[i] = i; }
并称之为如此:
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 // (ie malloc or some variant) then we // would need to call free(arr) }
C对数组的处理与Java有很大不同,因此你必须相应地调整你的想法。 C中的数组不是一等对象(也就是说,在大多数情况下,数组expression式并不保留它的“数组性”)。 在C语言中,除了当数组expression式是sizeof
或一元运算符时,“ T
”的N元素数组expression式将被隐式转换(“decay”)为一个types的expression式。 ,或者如果数组expression式是用来初始化声明中的另一个数组的string文字。
除此之外,这意味着您不能将数组expression式传递给一个函数,并将其作为数组types接收; 该函数实际上收到一个指针types:
void foo(char *a, size_t asize) { // do something with a } int bar(void) { char str[6] = "Hello"; foo(str, sizeof str); }
在对foo
的调用中,expression式str
从char [6]
转换为char *
,这就是为什么foo
的第一个参数被声明为char *a
而不是char a[6]
。 在sizeof str
,由于数组expression式是sizeof
运算符的操作数,因此它不会转换为指针types,因此您可以获得数组中的字节数(6)。
如果你真的感兴趣,你可以阅读丹尼斯·里奇的“C语言的发展”来理解这种治疗的来源。
其结果是函数不能返回数组types,这是好的,因为数组expression式不能作为赋值的目标。
最安全的方法是调用者定义数组,并将其地址和大小传递给应该写入的函数:
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); ... }
另一种方法是让函数dynamic分配数组并返回指针和大小:
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); ... }
在这种情况下,调用者负责使用free
库函数释放数组。
请注意,上面的代码中的dst
是一个简单的char
指针,而不是一个char
数组的指针。 C的指针和数组语义是这样的,你可以将下标运算符[]
应用于数组types或指针types的expression式; src[i]
和dst[i]
都将访问数组的第i
个元素(即使只有src
有数组types)。
您可以声明一个指向T
的N元素数组的指针,并执行类似的操作:
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的老版本期望SOME_SIZE
是一个编译时常量,这意味着函数将只能使用一个数组大小。 其次,在应用下标代码之前,必须先取消引用指针。 在处理multidimensional array时,指向数组的指针可以更好地工作。
在你的情况下,你正在堆栈上创build一个数组,一旦你离开函数作用域,数组将被释放。 相反,创build一个dynamic分配的数组并返回一个指针。
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); }
我并不是说这是针对给定问题的最佳解决scheme或首选解决scheme。 但是,记住函数可以返回结构可能是有用的。 虽然函数不能返回数组,但数组可以包装在结构中,函数可以返回结构,从而携带数组。 这适用于固定长度的数组。
#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; }
我邀请对这种技术的优点和缺点发表意见。 我没有打扰这样做。
这个可恶的实施呢?
array.h
#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; \ }
main.c中
#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; }
你的方法将返回一个本地堆栈variables,将会失败。 要返回一个数组,在函数外创build一个,通过地址传递给函数,然后修改它,或者在堆上创build一个数组并返回该variables。 两者都可以工作,但是第一个不需要任何dynamic的内存分配来使它正常工作。
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); }
你可以使用堆内存(通过malloc()调用),像这里报告的其他答案一样,但是你必须总是pipe理内存(每次调用你的函数时都使用free()函数)。 你也可以用一个静态数组来做到这一点:
char* returnArrayPointer() { static char array[SIZE]; // do something in your array here return array; }
你可以使用它而不用担心内存pipe理。
int main() { char* myArray = returnArrayPointer(); /* use your array here */ /* don't worry to free memory here */ }
在这个例子中,你必须在数组定义中使用static关键字来设置application-long数组的生命周期,所以在return语句后它不会被销毁。 当然,通过这种方式,您可以在整个应用程序生命周期中占用内存中的SIZE字节,因此请正确调整它的大小!
你可以使用这样的代码:
char *MyFunction(some arguments...) { char *pointer = malloc(size for the new array); if (!pointer) An error occurred, abort or do something about the error. return pointer; // Return address of memory to the caller. }
当你这样做的时候,内存应该被释放,通过传递地址来释放。
还有其他的select。 一个例程可能会返回一个指向某个数组(或者数组的一部分)的指针,这个数组是现有结构的一部分。 调用者可能会传递一个数组,而例程只是写入数组,而不是为新数组分配空间。
这里有一个不同的选项来传递string和返回string的一个小例子。
//include DPI #include "svdpi.h" //include the IO files #include <stdio.h> //include string functions #include <string.h> //include use of malloc #include <stdlib.h> //to add the ability to use printf // same inputs as defined in SV /* function declaration text char stream passed as pointer value and text2 passed as pointer reference */ char * return_string_in_c( char *text, char **text2) { char *fix="This variable cannot be changed although it is a pointer, just as example";/*fix allocation and constant*/ char dest[50]="Variable array created in a function:";/* String array max 50 chars allocated*/ char *out = malloc(sizeof(char) * 100);/* Dynamic string max 100 chars allocated*/ /* Concatenate input text and put in out of strcat*/ strcat(out, text);/* initialize out using strcat and text string*/ printf("fix : |%s|,dest : |%s|,text : |%s|,out : |%s|\n", fix,dest,text,out); *text2=dest;/* allocate pointer value with dest*/ *text2=out;/* now do the same overwrite allocate pointer value with out*/ return out; } /* main */ void main() { char text[100]="from_main_text_variable";/*max 100 chars allocated*/ char *text2;/* pointer not allocated*/ char *point = return_string_in_c(text, &text2);/* &text2 passing by reference*/ printf("Final destination string : |%s|\n", text2); printf("point output : |%s|\n", point); }
将你的数组声明为一个全局variables,这样每个函数都可以编辑它。 示例#include #include
char a[1000]; void edit(char b); main() { edit(a); printf("%s", a); } void edit(char b) { for(int i=0;i<sizeof(b);i++) a[i]=i; }