c - 为什么这个程序会崩溃?

标签 c variables arguments

此函数应返回一个字符串,其中包含第二个和后续参数的字符串表示形式,每个参数保留两位小数并以逗号分隔。第一个参数是后面的参数数量的计数。我做了一些研究,发现了 va_list 并尝试使用它。不幸的是,程序崩溃了,我不知道为什么。我发布此内容希望有人能够发现明显的错误或类似的内容。

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

char *to_string(int count,...)
{
     int i,x,k=0;
     float tmp;
     va_list valist;
     va_start(valist, count+1);
     char comma=',';
     char buffer[count*6];
     for(i=0;i<count;i++)
     {
        tmp=va_arg(valist, double)*100;
        x=tmp/100.0;
        k+=4;
        snprintf(buffer + k, "%C",comma);
        k++;
        snprintf(buffer + 1, "%.2f", x);
     }
     va_end(valist);
     printf("%s", buffer);
     return buffer;
}

int main()
{
   to_string(2,3.14876,6.123243);
}

最佳答案

正如评论中所述,您需要阅读 va_start() 的手册页和 snprintf()特别是,还要注意内存管理(您无法安全地返回指向本地(非静态)变量的指针)。

这是一段修改后的代码,可以解决已识别的问题并且不会崩溃(对于我来说,在运行 macOS Sierra 10.12.1 和 GCC 6.2.0 的 Mac 上)。

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

static char *to_string(char *buffer, size_t buflen, int count, ...)
{
    va_list valist;
    va_start(valist, count);
    char *data = buffer;
    for (int i = 0; i < count; i++)
    {
        int x = va_arg(valist, double) * 100;
        double tmp = x / 100.0 + 0.005;
        int n = snprintf(data, buflen, ",%.2f", tmp);
        if (n > (int)(buflen - 1))
        {
            fprintf(stderr, "%s: buffer not big enough\n", __func__);
            break;
        }
        data += n;
        buflen -= n;
    }
    va_end(valist);
    printf("%s: [%s]\n", __func__, buffer);
    return buffer;
}

int main(void)
{
    char buffer[80];
    printf("main: [%s]\n", to_string(buffer, sizeof(buffer), 2, 3.14876, 6.123243));
    return 0;
}

示例输出:

to_string: [,3.15,6.12]
main: [,3.15,6.12]

请注意,有一个您可能不想要的前导逗号。可以这样修复:

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

static char *to_string(char *buffer, size_t buflen, int count, ...)
{
    va_list valist;
    va_start(valist, count);
    char *data = buffer;
    const char *pad = "";
    for (int i = 0; i < count; i++)
    {
        int x = va_arg(valist, double) * 100;
        double tmp = x / 100.0 + 0.005;
        int n = snprintf(data, buflen, "%s%.2f", pad, tmp);
        if (n > (int)(buflen - 1))
        {
            fprintf(stderr, "%s: buffer not big enough\n", __func__);
            break;
        }
        pad = ",";
        data += n;
        buflen -= n;
    }
    va_end(valist);
    printf("%s: [%s]\n", __func__, buffer);
    return buffer;
}

int main(void)
{
    char buffer[80];
    printf("main: [%s]\n", to_string(buffer, sizeof(buffer), 2, 3.14876, 6.123243));
    printf("main: [%s]\n", to_string(buffer, sizeof(buffer), 20,
           6.67, 0.04, 8.81, 8.49, 3.50, 1.20, 4.28, 0.67, 1.93, 5.63,
           5.30, 8.43, 1.99, 4.62, 5.54, 7.21, 9.43, 2.02, 4.77, 0.29));
    return 0;
}

示例输出:

to_string: buffer not big enough
to_string: [3.15,6.12]
main: [3.15,6.12]
to_string: [6.67,0.04,8.82,8.50,3.50,1.20,4.29,0.68,1.93,5.63,5.30,8.44,1.99,4.62,5.54,7.21]
main: [6.67,0.04,8.82,8.50,3.50,1.20,4.29,0.68,1.93,5.63,5.30,8.44,1.99,4.62,5.54,7.21]

关于c - 为什么这个程序会崩溃?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40666606/

相关文章:

c - 在 gcc 编译期间获取内联失败警告

c - 在 C 中使用 fgets 从文件中读取字符串

c - 在 C 中声明枚举变量的最佳方法是什么?

python - Python 中的迭代器(循环变量)

python - 将一个函数的所有参数传递给另一个函数

python - 使用参数从 python 执行 Shell 脚本

c - 数组声明,并且不使用中间索引

c - 漂亮的树打印屏幕限制

php - 更新已设置的 php 变量

linux - 在命令中传递单词