【问题标题】:how can I append a char to a string allocating memory dynamically in C?如何在 C 中将 char 附加到字符串中动态分配内存?
【发布时间】:2019-03-06 21:42:01
【问题描述】:

我写了这段代码,但是在字符串的开头插入了垃圾:

void append(char *s, char c) {
    int len = strlen(s);
    s[len] = c;
    s[len + 1] = '\0';
}

int main(void) {
    char c, *s;
    int i = 0;
    s = malloc(sizeof(char));
    while ((c = getchar()) != '\n') {
        i++;
        s = realloc(s, i * sizeof(char));
        append(s, c);
    }   
    printf("\n%s",s);   
}

我该怎么做?

【问题讨论】:

  • 只需在s = calloc(1, sizeof(char)) 上更改s = malloc(sizeof(char)) 或在malloc *s = '\0'; 之后添加新行
  • 不要尝试在长度为 1 的缓冲区中存储 2 个字符。
  • s[len+1] = '\0'; 超出分配的内存范围。在第一次调用中,没有一个有效的字符串可以将strlen 应用到。
  • @Weather Vane,是的,但他是个聪明人;他在 append() 之前使用 reallock()
  • @purec 此时分配的内存大小为1,并且可能不包含字符串所需的终止0。它需要为2 的大小并被初始化。

标签: c string realloc


【解决方案1】:

您的代码中存在多个问题:

  • 您不断迭代,直到从标准输入流中读取换行符 ('\n')。如果在您读取换行符之前文件结束发生,这将导致无限循环,如果您从空文件重定向标准输入,则会发生这种情况。
  • c 应定义为 int,以便您可以正确测试 EOF
  • s 应始终为空终止,您必须将malloc() 之后的第一个字节设置为'\0',因为此函数不会初始化它分配的内存。
  • i 应初始化为 1,因此第一个 realloc() 将数组扩展 1 等。按照编码,您的数组太短了一个字节,无法容纳额外的字符。
  • 您应该检查内存分配失败。
  • 为了更好的风格,您应该在退出程序之前释放分配的内存
  • main() 应该返回一个 int,最好是 0 以表示成功。

这是一个更正的版本:

#include <stdio.h>
#include <stdlib.h>

/* append a character to a string, assuming s points to an array with enough space */
void append(char *s, char c) {
    size_t len = strlen(s);
    s[len] = c;
    s[len + 1] = '\0';
}

int main(void) {
    int c;
    char *s;
    size_t i = 1;
    s = malloc(i * sizeof(char));
    if (s == NULL) {
        printf("memory allocation failure\n");
        return 1;
    }
    *s = '\0';
    while ((c = getchar()) != EOF && c != '\n') {
        i++;
        s = realloc(s, i * sizeof(char));
        if (s == NULL) {
            printf("memory allocation failure\n");
            return 1;
        }
        append(s, c);
    }
    printf("%s\n", s);
    free(s);
    return 0;
}

【讨论】:

  • 有时需要一段时间才能得到完整的答案 - 做得很好。
  • @chux: רועי אבידן 的回答几乎没问题,但他对 EOF 的处理仍然不正确。
【解决方案2】:

当您调用 strlen 时,它会搜索 '\0' 字符来结束字符串。你的字符串中没有这个字符,strlen 的行为是不可预测的。 您的append 功能非常好。 另外,一件小事,您需要将return 0; 添加到您的主要功能中。 i 应该从 1 开始,而不是从 0 开始。 以下是它的外观:

int main(void){
   char *s;
   size_t i = 1;
   s = malloc (i * sizeof(char));//Just for fun. The i is not needed.
   if(s == NULL) {
   fprintf(stderr, "Coul'd not allocate enough memory");
   return 1;
   }
   s[0] = '\0';
   for(char c = getchar(); c != '\n' && c != EOF; c = getchar()) {//it is not needed in this case to store the result as an int.
      i++;
      s = realloc (s,i * sizeof(char) );
      if(s == NULL) {
             fprintf(stderr, "Coul'd not allocate enough memory");
             return 1;
      }
      append (s,c);
    }   
printf("%s\n",s);   
return 0;
}

感谢帮助我改进代码的 cmets(以及我的英语)。我并不完美:)

【讨论】:

  • sizeof (char) 根据定义为 1。乘以 1 是没有意义的。
  • 剩余错误:将getchar() 的结果存储在char 中(它返回int 是有原因的); i 可能溢出;缺少对realloc 的错误检查(它可以返回NULL)。
  • @WeatherVane size_t i = 1; 会更好。但这是一个小问题。
  • 好的,所以您没有解决任何问题,但添加了多余的演员表。
  • 虽然是一个附带问题,char c; while ((c = (char)getchar()) != '\n') { 应该是int c; while ((c = getchar()) != '\n' &amp;&amp; c != EOF) {。这很好地处理了来自getchar() 的所有可能的返回值,并避免了文件末尾的无限循环。
【解决方案3】:

内部realloc 需要多分配一个元素(用于尾随\0),并且您必须在开始循环之前初始化s[0] = '\0'

顺便说一句,您可以用strcat() 替换您的append 或这样写

size_t i = 0;
s = malloc(1);
/* TODO: check for s != NULL */
while ((c = getchar()) != '\n') {
        s[i] = c;
        i++;
        s = realloc(s, i + 1);
        /* TODO: check for s != NULL */
}
s[i] = '\0';

【讨论】:

    猜你喜欢
    • 2020-11-28
    • 2013-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-25
    • 2015-08-09
    • 1970-01-01
    相关资源
    最近更新 更多