如何在C语言中从函数返回一个字符数组?

14

那真的可能吗?假设我想返回一个由两个字符组成的数组

char arr[2];
arr[0] = 'c';
arr[1] = 'a';

从函数中返回什么类型呢?我的唯一选择是使用指针并将函数设置为void类型吗?到目前为止,我尝试了使用char*函数或char[]函数。显然你只能使用char(* [])类型的函数。我想避免使用指针的唯一原因是当函数遇到"return something;"时必须结束函数,因为"something"的值是一个字符数组(不是字符串!)它的大小可能会根据通过主函数传递给函数的值而改变。提前感谢任何回复的人。


函数应该返回 char *。你预见到什么问题? - Tarik
我尝试过了,但每次都会出现段错误。我只使用了一个char*函数并返回arr; 当我尝试输出时它会发生段错误。此外,当我从上面返回数组时,gcc会警告我正在尝试返回未转换的整数。 - user5042178
1
@AnnoyingQuestions 因为当数组在函数内部声明时,它被分配在函数的堆栈帧中,因此当返回它时,它会在返回后与函数一起被释放。 - Iharob Al Asimi
1
从技术上讲,它并没有被显式地释放。只是在函数之后使用它可能会导致未定义的行为,因为在此函数之后调用的函数可能已经覆盖了内存位置(在堆栈中)的内容。 - woodstok
1
如果你提供的这三行代码在一个函数中,那么当它超出作用域时,你试图返回一个局部变量,因此,是的,会发生段错误。它是一个数组这个事实与此无关。 - Lee Daniel Crocker
一个字符数组和一个字符串本质上是一样的,只不过字符串在末尾有一个NULL字符。它们都只是内存中连续的字节。 - Dan Korn
6个回答

25

你有几个选项:

1) 使用malloc()上分配你的数组,并返回指向它的指针。你还需要自己跟踪长度:

void give_me_some_chars(char **arr, size_t *arr_len)
{
    /* This function knows the array will be of length 2 */
    char *result = malloc(2);

    if (result) {
        result[0] = 'c';
        result[1] = 'a';
    }

    /* Set output parameters */
    *arr = result;
    *arr_len = 2;
}

void test(void)
{
    char *ar;
    size_t ar_len;
    int i;

    give_me_some_chars(&ar, &ar_len);

    if (ar) {
        printf("Array:\n");
        for (i=0; i<ar_len; i++) {
            printf(" [%d] = %c\n", i, ar[i]);
        }
        free(ar);
    }
}

2)调用者堆栈上分配数组空间,然后让被调用的函数填充它:

#define ARRAY_LEN(x)    (sizeof(x) / sizeof(x[0]))

/* Returns the number of items populated, or -1 if not enough space */
int give_me_some_chars(char *arr, int arr_len)
{
    if (arr_len < 2)
        return -1;

    arr[0] = 'c';
    arr[1] = 'a';

    return 2;
}

void test(void)
{
    char ar[2];
    int num_items;

    num_items = give_me_some_chars(ar, ARRAY_LEN(ar));

    printf("Array:\n");
    for (i=0; i<num_items; i++) {
        printf(" [%d] = %c\n", i, ar[i]);
    }
}

不要尝试这样做

char* bad_bad_bad_bad(void)
{
    char result[2];      /* This is allocated on the stack of this function
                            and is no longer valid after this function returns */

    result[0] = 'c';
    result[1] = 'a';

    return result;    /* BAD! */
}

void test(void)
{
    char *arr = bad_bad_bad_bad();

    /* arr is an invalid pointer! */
}

还有另一个完全有效的选项:return "ca"; - Dan Korn
3
当然,但是我认为你过于简化了这个问题。可以肯定的是,原帖中的代码比返回一些固定值要复杂得多(否则就没有意义)。 - Jonathon Reinhart
原帖中提出的问题本身非常简单。它是否背后还有更多复杂性,我无法说。你在做一个假设。 - Dan Korn
我可以这样做吗?
int comm_read_info(int file_i2c, unsigned char* buffer) { unsigned char* read_buffer = malloc(57); /* 此函数知道它是57个字节 */ if (i2c_read_bytes(file_i2c, read_buffer, sizeof(read_buffer)) != 0) { *buffer = result; return 0; } return -1; }
- Elephant
2
@Elephant 评论不是用来提问的 - 长段的代码难以阅读。你应该提出新问题。但是,这样做行不通;你在这里有一个类型不匹配:*buffer = result。你需要 comm_read_info(int file_i2c, unsigned char** buffer),它会返回指向缓冲区的指针。 - Jonathon Reinhart

2
你可以从函数中返回一个数组的指针,但是你不能返回指向本地数组的指针,引用将会丢失。
所以你有三个选择:
  1. Use a global variable:

     char arr[2];
    
     char * my_func(void){
         arr[0] = 'c';
         arr[1] = 'a';
         return arr;
     }
    
  2. Use dynamic allocation (the caller will have the responsibility to free the pointer after using it; make that clear in your documentation)

     char * my_func(void){
    
         char *arr;    
         arr = malloc(2);
         arr[0] = 'c';
         arr[1] = 'a';
    
         return arr;
     }
    
  3. Make the caller allocate the array and use it as a reference (my recommendation)

     void my_func(char * arr){
    
         arr[0] = 'c';
         arr[1] = 'a';
     }
    

如果你真的需要函数返回数组,你可以返回同一个引用:

char * my_func(char * arr){
    arr[0] = 'c';
    arr[1] = 'a';
    return arr;
}

1
还有另一个完全有效的选项:return "ca";。硬编码字符串根据定义是静态内存。 - Dan Korn

2

如果你的数组大小是预先确定的,实际上可以通过将其包装在结构体中返回该数组:

struct wrap
{
    char a[2] ;
} ;

struct wrap Get( void )
{
    struct wrap w = { 0 } ;

    w.a[0] = 'c';
    w.a[1] = 'a';

return w ;
}

1
你可以将数组传递给函数,并让函数修改它,就像这样。
void function(char *array)
 {
    array[0] = 'c';
    array[1] = 'a';
 }

然后

char array[2];

function(array);
printf("%c%c\n", array[0], array[1]);

如果您希望将其作为返回值,您应该使用动态内存分配。
char *function(void)
 {
    char *array;

    array = malloc(2);
    if (array == NULL)
        return NULL;
    array[0] = 'c';
    array[1] = 'a';

    return array;
 }

那么

char *array = function();
printf("%c%c\n", array[0], array[1]);
/* done using `array' so free it because you `malloc'ed it*/
free(array);

重要提示:

请注意,上面填充的数组不是字符串,因此您不能像这样操作

printf("%s\n", array);

因为"%s"需要传递匹配的字符串,在C语言中,除非其最后一个字符是'\0',否则数组不是字符串,所以对于一个由2个字符组成的字符串,你需要分配3个字符的空间并将最后一个字符设置为'\0'


如果你想要一个以 null 结尾的字符串,只需 return "ca"; - Dan Korn

-1
char* getCharArray()
{
  return "ca";
}

这并没有错。这是对原问题的一个完全有效的答案。 "上面的答案" 并没有以任何方式使其无效。我的解决方案没有返回指向本地变量的指针,因为硬编码字符串在定义上是静态的。该函数是完全安全和有效的。 - Dan Korn

-1

这个完美地运作:

int comm_read_data(int file_i2c, unsigned char** buffer)
{
    *buffer = malloc(BUFFER_SIZE);
    if (i2c_read_bytes(file_i2c, *buffer, BUFFER_SIZE) != 0)
    {
        return -1;
    }
    return BUFFER_SIZE;
}

然后调用该函数:

unsigned char* buffer;
int length = comm_read_data(file_i2c, &buffer);

/* parse the buffer here */

free(buffer);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接