为什么这个程序会崩溃?

时间:2016-11-17 23:01:02

标签: 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);
}

1 个答案:

答案 0 :(得分:2)

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

这是一段经过改进的代码,用于清理已发现的问题并且不会崩溃(对我来说,运行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]