使用C返回数组

use*_*919 133 c arrays pointers char

我是C的新手,我需要一些处理数组的方法的帮助.来自Java编程,我习惯于说int [] method()能够返回一个数组.但是,我发现使用C时,必须在返回数组时使用指针.作为一个新的程序员,我真的根本不理解这一点,即使我已经查看了许多论坛.

基本上,我正在尝试编写一个在C中返回char数组的方法.我将使用数组提供方法(让我们称之为returnArray).它将从前一个数组创建一个新数组并返回指向它的指针.我只是需要一些关于如何开始这个以及如何在从数组发出指针后读取指针的帮助.任何解释这个的帮助表示赞赏.

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

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?
} 
Run Code Online (Sandbox Code Playgroud)

函数的调用者

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?
}
Run Code Online (Sandbox Code Playgroud)

我还没有测试过这个,因为我的C编译器目前还没有工作,但我想弄明白这一点

Ed *_* S. 200

你不能从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?
} 
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

这样称呼它:

int main() {
    char *p = foo(10);
    if(p) {
        // do stuff with p
        free(p);
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

选项2:

填充调用者提供的预分配缓冲区(调用者分配buf并传递给函数)

void foo(char *buf, int count) {
    for(int i = 0; i < count; ++i)
        buf[i] = i;
}
Run Code Online (Sandbox Code Playgroud)

并称之为:

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)
}
Run Code Online (Sandbox Code Playgroud)

  • 选项3 :(静态数组) (26认同)
  • 选项4:返回包含固定大小数组的结构. (5认同)
  • @moooeeeep:是的,我故意将其保留为简单,但是,您可以返回指向函数内声明的静态数据的指针. (4认同)
  • @ user1506919:我实际上更喜欢选项2,因为很清楚谁分配和释放内存,但我会为你添加一个例子. (3认同)
  • 选项 5:返回一个包含固定大小数组的联合。 (2认同)
  • @CrazySynthax:因为你要返回那个 `int` 的副本。你不能返回一个数组,语言不允许。所以你返回一个指向坏内存的指针。一个更好的类比是返回一个 `int*`,它指向函数本地的 `int`。 (2认同)

Joh*_*ode 24

C对阵列的处理与Java 非常不同,你必须相应地调整你的思路.C中的数组不是第一类对象(也就是说,数组表达式在大多数情况下都不会保留它的"数组").在C中,类型为"N元素数组"的表达式T将被隐式转换("衰减")为"指向T" 的类型的表达式,除非数组表达式是sizeof或一元运算&符的操作数,或者如果数组表达式是一个字符串文字,用于初始化声明中的另一个数组.

除此之外,这意味着您无法将数组表达式传递给函数并将其作为数组类型接收; 该函数实际上接收指针类型:

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

int bar(void)
{
  char str[6] = "Hello";
  foo(str, sizeof str);
}
Run Code Online (Sandbox Code Playgroud)

在调用中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);
  ...
}
Run Code Online (Sandbox Code Playgroud)

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

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);
  ...
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,调用者负责使用free库函数释放数组.

注意,dst在上面的代码中是一个简单的指针char,而不是指向数组的指针char.C的指针和数组语义是这样的,您可以将下标运算符[]应用于数组类型指针类型的表达式; both src[i]dst[i]将访问i数组的第th个元素(即使只有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]);
  ...
}
Run Code Online (Sandbox Code Playgroud)

以上几个缺点.首先,旧版本的C期望SOME_SIZE是编译时常量,这意味着该函数只能使用一个数组大小.其次,在应用下标之前必须取消引用指针,这会使代码变得混乱.当您处理多维数组时,指向数组的指针会更好.

  • 您链接到"C的开发"已经破了......看起来它应该引导我们:https://www.bell-labs.com/usr/dmr/www/chist.html (2认同)

pyr*_*ade 9

这个美味邪恶的实施怎么样?

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;    \
}
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

  • 这非常美味,足以引起我的好奇心.你能解释一下你在那里做了什么,或者建议你读一下这种美味吗?提前致谢. (2认同)

men*_*ngo 8

您可以像此处报告的其他答案一样使用堆内存(通过malloc()调用)来执行此操作,但您必须始终管理内存(每次调用函数时都使用free()函数)。您也可以使用静态数组来做到这一点:

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

// do something in your array here

return array; 
}
Run Code Online (Sandbox Code Playgroud)

您可以使用它而不必担心内存管理。

int main() 
{
char* myArray = returnArrayPointer();
/* use your array here */
/* don't worry to free memory here */
}
Run Code Online (Sandbox Code Playgroud)

在此示例中,您必须在数组定义中使用 static 关键字将数组生命周期设置为 application-long,因此它不会在 return 语句后销毁。当然,通过这种方式,您在整个应用程序生命周期中都会在内存中占用 SIZE 字节,因此请正确调整大小!


Man*_*Way 6

在您的情况下,您正在堆栈上创建一个数组,一旦您离开函数范围,该数组将被释放.相反,创建一个动态分配的数组并返回指向它的指针.

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

}
Run Code Online (Sandbox Code Playgroud)

  • C中没有`new`运算符.这就是C++. (2认同)

小智 6

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

    #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;
    }
Run Code Online (Sandbox Code Playgroud)

我邀请评论这项技术的优点和缺点.我没有打算这样做.

  • 不清楚为什么这不是公认的答案。问题不在于是否可以返回指向数组的指针。 (2认同)