【问题标题】:How can I return a character array from a function in C?如何从 C 中的函数返回字符数组?
【发布时间】:2015-09-12 15:41:08
【问题描述】:

这可能吗? 假设我要返回一个包含两个字符的数组

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

来自一个函数。我什至使用什么类型的功能?我唯一的选择是使用指针并使函数无效吗?到目前为止,我已经尝试过使用 char* 函数或 char[]。显然你只能拥有 char(*[]) 的功能。我想避免使用指针的唯一原因是函数必须在遇到“返回某些东西”时结束;因为“某物”的值是一个字符数组(不是字符串!),它可能会根据我通过主函数传递给函数的值而改变大小。感谢任何提前回复的人。

【问题讨论】:

  • 函数应该返回 char *。你预见到什么问题?
  • 我试过了,但每次都会出现段错误。我只是使用 char* 函数并返回 arr;当我尝试输出时它会出现段错误。 gcc 还警告我,当我从上面返回数组时,我正在尝试返回整数而不进行强制转换
  • @AnnoyingQuestions 因为一个数组在函数内部声明时分配在函数的堆栈框架中,因此在返回它时,它会在返回后立即与函数一起释放。
  • 从技术上讲,它没有被明确地释放。只是在函数之后使用它可能会导致未定义的行为,因为在此函数之后调用的函数可能会覆盖内存位置(在堆栈中)的内容
  • 如果你给我们的三行代码在一个函数中,那么你试图在它超出范围后返回一个本地,所以是的,这将是段错误。它是一个数组的事实与它无关。

标签: c arrays function pointers character


【解决方案1】:

您有多种选择:

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)调用者stack上为数组分配空间,并让被调用函数填充它:

#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";
  • @DanKorn 当然,但我认为您过度简化了问题。可以肯定地说 OP 的代码比返回一些固定值更复杂(没有意义)。
  • 原帖所说的问题本身就很简单。我不能说它背后是否有更多的复杂性。你在做一个假设。
  • 我可以关注吗? int comm_read_info(int file_i2c, unsigned char* buffer) { unsigned char* read_buffer = malloc(57); /* this func knows that it is 57 bytes */ if (i2c_read_bytes(file_i2c, read_buffer, sizeof(read_buffer)) != 0) { *buffer = result; return 0; } return -1; }
  • @Elephant 评论不是用来提问的——长段代码是不可读的。你应该ask a new question。但是不,那是行不通的;你这里有一个类型不匹配:*buffer = result 你需要comm_read_info(int file_i2c, unsigned char** buffer) 它返回一个指向缓冲区的指针。
【解决方案2】:

由于你有一个预先确定的数组大小,如果你用结构包装它,你实际上可以返回数组:

struct wrap
{
    char a[2] ;
} ;

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

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

return w ;
}

【讨论】:

    【解决方案3】:

    你可以从函数中返回数组的指针,但是你不能返回指向本地数组的指针,引用会丢失。

    所以你有 3 个选择:

    1. 使用全局变量:

       char arr[2];
      
       char * my_func(void){
           arr[0] = 'c';
           arr[1] = 'a';
           return arr;
       }
      
    2. 使用动态分配(调用者有责任在使用后释放指针;在您的文档中明确说明)

       char * my_func(void){
      
           char *arr;    
           arr = malloc(2);
           arr[0] = 'c';
           arr[1] = 'a';
      
           return arr;
       }
      
    3. 让调用者分配数组并将其用作参考(我的建议)

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

    如果确实需要函数返回数组,可以返回相同的引用:

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

    【讨论】:

    • 还有另一个完全有效的选项:return "ca";。根据定义,硬编码字符串是静态内存。
    【解决方案4】:

    你可以将数组传递给函数,让函数修改它,像这样

    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";
    【解决方案5】:
    char* getCharArray()
    {
      return "ca";
    }
    

    【讨论】:

    • 没有错。这是对原始问题的完全有效的答案。 “上述答案”不会以任何方式使其无效。我的解决方案不存在返回指向局部变量的指针的问题,因为硬编码字符串根据定义是静态的。该函数完全安全有效。
    【解决方案6】:

    这很完美:

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

    【讨论】:

      猜你喜欢
      • 2020-02-14
      • 2014-04-11
      • 2013-11-22
      • 2013-03-25
      • 2013-10-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多