使用C返回一个数组

我对C相对陌生,我需要一些处理数组的方法的帮助。来自Java编程,我习惯于能够说int [] method(),以返回一个数组。然而,我发现在C语言中,当你返回数组时,你必须使用指针。作为一个新程序员,我真的不明白这一点,即使我浏览了许多论坛。

基本上,我试图写一个方法,返回一个字符数组在c。我将提供方法(让我们称之为returnArray)与一个数组。它将从前一个数组创建一个新数组,并返回指向该数组的指针。我只是需要一些帮助,如何得到这个开始,以及如何读取指针一旦它被发送出数组。

数组返回函数的建议代码格式

char *returnArray(char array []){
char returned [10];
// Methods to pull values from the array, interpret
// them, and then create a 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?
}

我还没有测试这个,因为我的C编译器还没有工作,但我想弄清楚这一点。

497124 次浏览

在本例中,您在堆栈上创建了一个数组,一旦离开函数作用域,该数组将被释放。相反,创建一个动态分配的数组并返回指向它的指针。

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);


}

您的方法将返回一个局部堆栈变量,该变量将严重失败。要返回一个数组,请在函数外部创建一个数组,按地址将其传递到函数中,然后修改它,或者在堆上创建一个数组并返回该变量。两者都可以工作,但是第一个不需要任何动态内存分配来使其正确工作。

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);
}

在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创建时具有自动存储持续时间,一旦它离开声明作用域,即函数返回时,对它的引用将变得无效。

您需要动态分配函数内部的内存,或者填充调用方提供的预分配缓冲区。

选项1:

动态分配函数内部的内存(调用者负责释放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
// (i.e. malloc or some variant) then we
// would need to call free(arr)
}

你可以使用这样的代码:

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.
}

当您这样做时,稍后应该通过将地址传递给free来释放内存。

还有其他选择。例程可以返回指向某个现有结构的一部分的数组(或数组的一部分)的指针。调用方可能传递一个数组,例程只向数组中写入,而不为新数组分配空间。

C语言对数组的处理是非常不同于Java,你必须相应地调整你的思想。C语言中的数组不是第一类对象(也就是说,数组表达式不会保留它的“数组性”;在大多数情况下)。在C语言中,类型为“N-element array of T"将被隐式转换("decay")为指向__abc0的指针类型的表达式,除非数组表达式是sizeof或单元&操作符的操作数,或者数组表达式是一个字符串字面值,用于在声明中初始化另一个数组。

除此之外,这意味着你不能将数组表达式传递给函数并让它接收作为数组类型;函数实际接收一个指针类型:

void foo(char *a, size_t asize)
{
// do something with a
}


int bar(void)
{
char str[6] = "Hello";
foo(str, sizeof str);
}

在对foo的调用中,表达式str从类型char [6]转换为类型char *,这就是为什么foo的第一个参数声明为char *a而不是char a[6]。在sizeof str中,由于数组表达式是sizeof操作符的操作数,因此它不会转换为指针类型,因此您将得到数组中的字节数(6)。

如果你对真的感兴趣,你可以阅读Dennis Ritchie的C语言的发展来了解这种治疗方法的来源。

结果是函数不能返回数组类型,这很好,因为数组表达式也不能成为赋值的目标。

最安全的方法是调用者定义数组,并将其地址和大小传递给应该写入数组的函数:

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);
...
}

另一种方法是函数动态分配数组并返回指针和大小:

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的指针和数组语义是这样的:你可以将下标操作符[]应用于数组类型的表达式指针类型;src[i]dst[i]都将访问数组的__abc6 '号元素(即使只有src具有数组类型)。

可以声明一个指向n元素数组T的指针,并做类似的事情:

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是一个编译时常量,这意味着该函数只适用于一个数组大小。其次,在应用下标之前必须解除对指针的引用,这会使代码变得混乱。在处理多维数组时,指向数组的指针工作得更好。

使用这个美味的邪恶实现:

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;    \
}

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;
}

你可以像这里报告的其他答案一样使用堆内存(通过malloc ()调用),但你必须始终管理内存(每次调用函数时使用free ()函数)。

你也可以用一个静态数组:

char* returnArrayPointer()
{
static char array[SIZE];


// Do something in your array here


return array;
}

然后您就可以使用它而不用担心内存管理。

int main()
{
char* myArray = returnArrayPointer();
/* Use your array here */
/* Don't worry to free memory here */
}

在这个例子中,你必须在数组定义中使用static关键字将数组的生命周期设置为application-long,这样它就不会在return语句后被销毁。

当然,通过这种方式,您在整个应用程序生命周期中占用内存中的SIZE字节,所以要适当地调整它的大小!

我并不是说这是给定问题的最佳解决方案或首选解决方案。但是,记住函数可以返回结构可能是有用的。虽然函数不能返回数组,但数组可以被包装在结构体中,函数可以返回结构体,从而携带数组。这适用于固定长度的数组。

    #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;
}