【问题标题】:Can't copy string to an array of strings in C无法将字符串复制到C中的字符串数组
【发布时间】:2016-01-05 07:58:27
【问题描述】:

我正在尝试遍历我的链表并将每个节点字段组合成一个字符串,然后将该字符串添加到一个字符串数组中。

void listToArray(){
   //create array of strings
    char *list[numNodes];
    int i = 0, n;

  while(head != NULL){
    // add string to array
    printf("[%d] %s %s:%d\n ", i, head->fileName, head->ip, head->port);
    n = sprintf(list[i], "[%d] %s %s:%d\n", i, head->fileName, head->ip, head->port);
    head = head->next;
    printf("%s\n", list[i]);
    i++;

 }

printf 语句工作正常,这表明不是节点的字段导致问题,而是当我执行我的 sprintf 语句将字符串复制到数组的索引中时。我得到一个分段错误。

【问题讨论】:

  • 你必须为list[i]分配内存
  • 当您声明时,char *list[numNodes]; 它为char 指针数组分配空间,但它们尚未初始化。您需要分配它们(例如,对每个元素使用mallocfor ( i = 0; i < numNodes; i++ ) list[i] = malloc(stringSize);)。
  • 你在哪里为每个非列表分配内存? list 被定义为一个指向字符数组的指针,但它不指向任何东西。你需要 malloc 什么的。我要做的是在堆栈上创建一个名为 temp 的字符数组,它足够大(可能 128 个字符?),例如 char temp[128]; 然后 sprintf 进入 temp 然后设置 list[i] = strdup(temp);
  • 而不是sprintf(),使用asprintf(),它将自动分配足够大的内存来保存包含空字节终止符的结果字符串。然而,这是一个 GNU 扩展,在 *BSD 中也可用,但在 POSIX 中不可用。
  • 我遇到了分段错误。 -- 祝你好运!更糟糕的事情可能会发生(例如,似乎以您认为正确的方式“工作”,但后来却以致命的方式失败)。

标签: c arrays string printf


【解决方案1】:

您没有初始化 char 指针数组 - sprintf 正在将数据写入某个随机位置。

在调用 sprintf 之前,应使用 malloc 将每个 char 指针初始化为缓冲区。

【讨论】:

  • 在不知道字符串大小的情况下如何做到这一点?
  • 您可以先使用snprintf获取格式化字符串的大小,然后分配,然后在分配的字符串上使用sprintf
  • @owacoder - 如man snprintf(3) 所述,这将使用 C99 标准工作 - 关于 snprintf() 的返回值,SUSv2 和 C99 相互矛盾:当使用 size=0 调用 snprintf() 时然后 SUSv2 规定了一个小于 1 的未指定返回值,而 C99 在这种情况下允许 str 为 NULL,并给出返回值(一如既往)作为输出字符串足够大时将写入的字符数. - 你的建议没有错,只是把这个笔记放在那里给 OP 和未来的读者。
  • @alvits - 那么您对可移植性有何建议?或者有没有便携的方法?
  • @owacoder - 我还没有找到可移植的方法。但我确实编写了一个包含在编译器指令中的 asprintf() 的本地实现,以便在非 GNU 系统上使用。简而言之,这个本地的asprintf() 会做GNU 扩展asprintf() 会做的事情。我很想听听任何找到便携式方法的人的意见。
【解决方案2】:

你只声明

char *list[numNodes];

但不为它们分配内存。在使用list[i] 之前使用malloc 分配内存。要知道从sprintf 生成的字符串的大小,请使用snprintf。感谢user3121023 找到我们这个功能。

void listToArray(){
   //create array of strings
    char *list[numNodes];
    int i = 0, n;

  while(head != NULL){
    printf("[%d] %s %s:%d\n ", i, head->fileName, head->ip, head->port);

    n = snprintf(NULL, 0, "[%d] %s %s:%d\n", i, head->fileName, head->ip, head->port);
    list[i] = malloc((n+1)*sizeof(char));

    n = sprintf(list[i], "[%d] %s %s:%d\n", i, head->fileName, head->ip, head->port);
    head = head->next;
    printf("%s\n", list[i]);
    i++;

 }

【讨论】:

  • 快速说明:如果您使用 GCC,还有asprintf 会为您分配。
【解决方案3】:

list 已定义,但每个元素中没有/随机指针。上面的答案是完整的,但可以稍微简化一下:

void listToArray(){
    //create array of strings
    char *list[numNodes];
    char buf[5000];
    int i = 0, n;

    while (head != NULL) {
        snprintf(buf,sizeof(buf),"[%d] %s %s:%d\n ",
            i,head->fileName,head->ip,head->port);

        // add string to array
        list[i] = strdup(buf);

        // output
        fputs(list[i],stdout);

        head = head->next;
        i++;
    }
}

您只需要执行一次 printf/sprintf。那是缓慢的部分。执行一次 snprintf 和 strdup 比执行 2-3 次 *printf 调用更快、更简单。我猜您每个项目只需要一个输出行,其余的用于调试。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-11
    • 2015-03-23
    • 1970-01-01
    • 1970-01-01
    • 2020-11-04
    • 1970-01-01
    • 2020-08-02
    • 2018-04-28
    相关资源
    最近更新 更多