【问题标题】:How to dynamically expand a string in C如何在C中动态扩展字符串
【发布时间】:2010-03-18 08:45:57
【问题描述】:

我有一个函数可以递归地对一组数字进行一些计算。我还想通过传递上一个计算中的字符串并将其与当前操作连接来漂亮地打印每个递归调用中的计算。示例输出可能如下所示:

3
(3) + 2
((3) + 2) / 4
(((3) + 2) / 4) x 5
((((3) + 2) / 4) x 5) + 14
... and so on

所以基本上,第二个调用得到 3 并附加 + 2 ,第三个调用得到传递 (3) + 2 等等。我的递归函数原型如下所示:

void calc_rec(int input[], int length, char * previous_string);

我写了 2 个辅助函数来帮助我进行操作,但是当我测试它们时它们崩溃了:

/**********************************************************************
 * dynamically allocate and append new string to old string and return a pointer to it
 **********************************************************************/
 char * strapp(char * old, char * new)
 {
     // find the size of the string to allocate
     int len = sizeof(char) * (strlen(old) + strlen(new));

     // allocate a pointer to the new string
     char * out = (char*)malloc(len);

     // concat both strings and return
     sprintf(out, "%s%s", old, new);

     return out;
 }

/**********************************************************************
 * returns a pretty math representation of the calculation op
 **********************************************************************/
 char * mathop(char * old, char operand, int num)
 {
     char * output, *newout;
     char fstr[50]; // random guess.. couldn't think of a better way.
     sprintf(fstr, " %c %d", operand, num);
     output = strapp(old, fstr);
     newout = (char*)malloc( 2*sizeof(char)+sizeof(output) );
     sprintf(newout, "(%s)", output);
     free(output);
     return newout;  
 }


void test_mathop()
{
    int i, total = 10;
    char * first = "3";
    printf("in test_mathop\n");
    while (i < total)
    {
        first = mathop(first, "+", i);
        printf("%s\n", first);
        ++i;
    }
}

strapp() 返回一个指向新添加的字符串(有效)的指针,而 mathop() 应该采用旧的计算字符串 ("(3)+2"),一个 char 操作数 ('+', '-' , etc) 和一个 int,并返回一个指向新字符串的指针,例如“((3)+2)/3”。知道我在哪里搞砸了吗?谢谢。

【问题讨论】:

  • sizeof(output) 将为您提供指针的大小。与 strlen 非常不同。
  • 你还没有初始化i!!
  • 您可能应该删除 sizeof (char),它只是一种写 1 的大写方式,会使事情变得混乱并且(最坏的情况)会增加混乱。
  • @Agnel 为什么不添加这些作为答案?我会说你应该得到一些 + 的观察结果:-)
  • @Péter Török - 我对这些回复不太自信。但你说得有道理……

标签: c string malloc


【解决方案1】:

你应该为终止的 0 分配一个额外的字节。

你应该在这里使用strlen而不是sizeof

newout = (char*)malloc( 2*sizeof(char)+sizeof(output) );

Sizeof 返回char* 的大小(在平均系统上类似于4),而不是output 指向的字符串的长度。

此外,正如@Agnel 正确指出的那样,i 未初始化,尽管这不会使您的程序崩溃,只需执行随机次数的循环即可。

另外,我建议使用 strstr strcat 连接您的字符串。

【讨论】:

  • 我以为strstr是在另一个字符串中找一个子字符串
  • 他不仅要为后面的 \0 分配空间,而且还必须把 \0 放在那里。
  • @sharptooth 确实是好点,值得一提。虽然strcat 会自动处理。
【解决方案2】:

我可以看到的一个直接问题是:

int len = sizeof(char) * (strlen(old) + strlen(new));

不为末尾的NULL 字符分配空间。所以你需要额外分配一个字符。

【讨论】:

  • NULL char 被 sizeof(char) 覆盖
  • @kenny 不,不是。自己测试一下。
  • @kenny:可以说旧的是“1”,新的是“2”。两者的 strlen 均为 1。现在您想将它们连接成一个字符串。它应该容纳 '1'、'2' 和 '\0',以标记字符串的结尾。所以我们需要一个额外的字符来表示字符串长度的总和。
【解决方案3】:

试试这个,对于初学者来说:

char * append_strings(const char * old, const char * new)
{
    // find the size of the string to allocate
    size_t len = strlen(old) + strlen(new) + 1;

    // allocate a pointer to the new string
    char *out = malloc(len);

    // concat both strings and return
    sprintf(out, "%s%s", old, new);

    return out;
}

这只是您的代码,有许多修复:

  • 输入字符串没有改变,所以应该声明为const
  • 将新缓冲区所需的大小加一,以便为终止符留出空间。
  • 最好将字符串长度存储在size_t 类型的变量中。
  • 删除了sizeof (char) 不必要的缩放。
  • 不要返回malloc()
  • 不要定义名称以str 开头的函数,这是一个保留空间。评论者指出,谢谢!

为了提高性能,您可以利用在两个输入上都调用strlen()这一事实,并避免使用sprintf()

char * append_strings(const char * old, const char * new)
{
    // find the size of the string to allocate
    const size_t old_len = strlen(old), new_len = strlen(new);
    const size_t out_len = old_len + new_len + 1;

    // allocate a pointer to the new string
    char *out = malloc(out_len);

    // concat both strings and return
    memcpy(out, old, old_len);
    memcpy(out + old_len, new, new_len + 1);

    return out;
}

这应该会快一点,但我还没有对其进行基准测试。请注意最终的memcpy() 是如何包含new 字符串中的终止符的,因此无需手动设置。

【讨论】:

  • 从技术上讲,给函数命名以“str”开头是个坏主意。
  • @sgm 你是对的,但是 IMO 这应该是对原始问题的评论。
  • @sgm:你说的很对,我会编辑把它作为改进。
【解决方案4】:

感谢所有回复,他们非常有帮助 - 尤其是 strcat 建议并发现我需要为 '\0' 字符分配空间。我最终使用 realloc 来“拉伸”字符串并附加前导和尾随字符。我还消除了 strapp (append_strings) 函数并让它在 mathop 中工作。方法如下:

/**********************************************************************
 * returns a pretty math representation of the calculation op
 **********************************************************************/
 char * mathop(char * previous, char operand, float num)
 {
     char *output, *temp, calculation[50];
     size_t newlen;

     // copy the previous data into the temp string     
     temp = (char*)malloc( strlen(previous) + 1 );
     output = (char*)malloc(2);

     strcpy(temp, previous);
     strcpy(output, "(\0");

     // create the string portion to append to the output
     sprintf(calculation, " %c %.1f)\0", operand, num);

     // reallocate the output to append the additional string
     newlen = strlen(temp) + strlen(calculation) + 1;
     temp = realloc(temp, newlen);

     // append the new data to output
     strcat(temp, calculation);
     output = realloc(output, strlen(temp) + 2);
     strcat(output, temp);
     printf("%s\n", output);

     free(temp);
     return output;  
 }

再次感谢!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-29
    • 2013-07-24
    • 2021-06-18
    • 2020-08-23
    • 2021-07-12
    • 2019-05-27
    • 2018-11-26
    • 1970-01-01
    相关资源
    最近更新 更多