【问题标题】:C returning const char pointer or char pointer from a functionC 从函数返回 const char 指针或 char 指针
【发布时间】:2016-06-10 19:59:17
【问题描述】:

我想更好地理解这一点,所以我在这里问。我编写了一个读取文件并将内容作为字符串返回的函数。它目前被实现为返回char*,因为它看起来更容易,但我想知道这是否是正确的方法,因为许多使用char 数组的C 函数原型将它们作为const char 使用。我说它更容易的原因是,一旦你读取了所有数据,如果你想返回一个const char,我必须创建一个精确大小的新缓冲区并将数据复制到那里,而不是仅仅重新分配缓冲到正确的大小并返回在堆上分配的指针。

我的问题,返回值应该是const char* 还是char*

这是一个小代码:

char *get_resource(char **res, const char *filename) {
    size_t count = ((strlen(resource_dir) + strlen(filename) + 1));
    *res = calloc(count, sizeof(char));
    strncpy(*res, resource_dir, resource_dir_len);
    strncat(*res, filename, strlen(filename));
    return *res;
}

或者这个:

char *read_file(char **data, const char *file_path) {
    FILE *fp;
    size_t buffer = 4096;
    size_t index = 0;
    int ch;

    fp = fopen(file_path, "r");
    if (fp == NULL) {
        printf("failed to open file: %s\n", file_path);
        return "-1\0";
    }

    (*data) = calloc(buffer, sizeof(char));
    while (EOF != (ch = fgetc(fp))) {
        (*data)[index] = (char)ch;
        ++index;
        if (index == buffer - 1) {
            buffer = buffer * 2;
            data = realloc(data, buffer);
            if (data != NULL) {
                printf("buffer not large enough, reallocating %zu bytes to "
                       "load %s\n",
                       buffer, file_path);
            } else {
                printf("failed to realloc %zu bytes to load %s\n", buffer,
                       file_path);
            }
        }
    }
    (*data) = realloc((*data), (sizeof(char) * (index + 1)));
    (*data)[index] = '\0';

    fclose(fp);
    return *data;
}

【问题讨论】:

  • 第二个代码的返回值应该是const char*,因为函数可能会返回从字符串字面量转换而来的指针。
  • 第一个代码 sn-p 错误地使用了strncpy / strncatstrncat 函数仅在第一个参数指向一个以 null 结尾的字符串时才有效,但 strncpy 不会像您使用它的方式那样为 null 终止(假设 resource_dir_len == strlen(resource_dir))。建议不要使用strncpy,您可以使用strcpysnprintf
  • 不要使用 strncpy 它不会像你想的那样。
  • 为什么将指针返回到结果缓冲区两次:通过第一个参数和返回值?您可以将char* 传递给请求const char* 的函数,但反之则不行。 (也许,我误解了你的问题。)
  • 我看到帖子说使用 strncpy 因为它更安全,然后我看到不使用 strncpy 因为它不是。有时这些事情有点难以跟上,从上面的粗体陈述来看,我认为我不应该使用它,所以我会改变它。 @MartinZabel 我这样做是为了可以连续进行多个函数调用。我传入返回的变量的原因是为了在执行行内函数时不会发生内存泄漏。

标签: c arrays string pointers constants


【解决方案1】:

在 cmets 中已经解释了一些错误,我不会重复,但我建议您尽快修复。
现在,在键入定义时,您必须考虑对来自函数内部和外部的数据的预期或要求行为是什么。
在您的情况下,您需要在函数内部有一个可更改的数据缓冲区,但在外部需要一个不可更改的数据缓冲区。澄清了这一点,您可以因此键入函数,然后使用强制转换:

const char *get_resource(const char** InRes, const char* filename)
{
    char *res;
    size_t count = ((strlen(resource_dir) + strlen(filename) + 1));
    if (*InRes)
    {
        res = realloc((void *)*InRes, count * sizeof(char));
        if (!res)
            return NULL;
    }
    else
    {
        res = calloc(count, sizeof(char));
        if (!res)
            return NULL;
    }
    *InRes = res;
    strcpy(res, resource_dir);
    strcat(res, filename);
    return res;
}

注意不需要强制转换的返回,因为将数据设为 const 并不违反数据性质,反之亦然(例如,制作可更改的常量数据)。

【讨论】:

  • 为什么res在声明时初始化? res 无论如何都会在 calloc 行中更新。并且传入的const char * 不再通过*InRes 更新。
  • @MartinZabel 谢谢马丁。我错过了。我已经使用更新源缓冲区的代码更新了示例。如果InRes在重新分配之前已经存在。
猜你喜欢
  • 1970-01-01
  • 2018-04-05
  • 2021-02-14
  • 1970-01-01
  • 2021-01-26
  • 2013-06-12
  • 2021-08-18
  • 2021-11-26
  • 2011-12-05
相关资源
最近更新 更多