c中的snprintf问题

时间:2016-05-18 00:47:22

标签: c printf malloc

在下面的例子中,数据没有按预期设置,也没有设置data_handler。

int main() {

char    *data;
char    *data_handler;
int      i = 0;
int      len , req;
char     test[10] = "test";

for(; i<10; i++){

    req = snprintf(NULL, 0 , "[%s] ", test);

    printf("%d --> req \n", req);
    if (data == NULL) {
        data = (char *) malloc ((sizeof(char) * req) + 1);
        data_handler = data;
    } else {
        data_handler = data + len;
        data_handler = (char *) malloc ((sizeof(char) * req) +1);
    }

    len += snprintf(data_handler, sizeof(data) , "[%s] ", test);

    printf("\nData --> %s\n", data);
    printf("\nData Handler --> %s\n", data_handler);
} 

printf ("%s", data);

}

该程序的意图是在字符串中追加10次测试。 (试验指针),但我得到了以下输出。

7 --> req 

Data --> (��

Data Handler --> [te
7 --> req 

Data --> (��

Data Handler --> [te
7 --> req 

Data --> (��

Data Handler --> [te
7 --> req 

Data --> (��

Data Handler --> [te
7 --> req 

Data --> (��

Data Handler --> [te
7 --> req 

Data --> (��

Data Handler --> [te
7 --> req 

Data --> (��

Data Handler --> [te
7 --> req 

Data --> (��

Data Handler --> [te
7 --> req 

Data --> (��

Data Handler --> [te
7 --> req 

Data --> (��

Data Handler --> [te
(��
Exited: ExitFailure 5

3 个答案:

答案 0 :(得分:1)

本地变量不会自动初始化,

char *data;

离开data未初始化,这意味着它没有存储在其中的值,它是一个随机值,可能被认为是垃圾并且是不可预测的,但它很可能不是NULL,所以测试是错误的,并且在没有首先初始化它的情况下打印data

此外,sizeof运算符返回类型的大小而不是分配的大小。您应该保留分配的大小,以便以后使用它。 sizeof运算符也为您提供了数组的大小,但data不是数组,而是指针。

最后:

  1. 不要转换malloc()的返回值。 Read here for more about it
  2. 请勿使用sizeof(char),因为根据定义,它是=== 1

答案 1 :(得分:1)

除了讨论的其他问题之外,您的代码还会严重泄漏内存。您不能简单地每次迭代继续malloc data_handler。执行此操作时,将覆盖先前分配的块的地址,从而失去free先前分配的内存的能力。相反,您必须realloc原始内存块,保留指向内存块起始地址的指针data,然后相应地更新data_handler。 这是一个基本的内存管理问题。

相反,您似乎尝试执行以下操作。如果我误解了你的目标,我会道歉,否则你的代码没有意义:

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

int main (void) {

    char *data = NULL;
    char *data_handler = NULL;
    int i = 0, len = 0, req = 0;
    char test[10] = "test";

    req = snprintf (NULL, 0, "[%s] ", test);
    printf ("%d --> req\n", req);

    for (; i < 10; i++) {

        if (data == NULL) {
            data = malloc (req + 1);
            data_handler = data;
        }
        else {
            char *tmp = realloc (data, len + req + 1);  /* realloc data */
            if (!tmp) { /* validate */
                fprintf (stderr, "realloc() error: virtual memory exhausted.\n");
                return 1;
            }
            data = tmp;                 /* assign tmp to data  */
            data_handler = data + len;  /* update data_handler */
        }

        len += snprintf (data_handler, sizeof test, "[%s] ", test);

        printf ("-- (len: %d)\nData         --> %s\n", len, data);
        printf ("Data Handler --> %s\n", data_handler);
    }
    putchar ('\n');
    free (data);

    return 0;
}

示例使用/输出

$ ./bin/snprintfnoinit
7 --> req
-- (len: 7)
Data         --> [test]
Data Handler --> [test]
-- (len: 14)
Data         --> [test] [test]
Data Handler --> [test]
-- (len: 21)
Data         --> [test] [test] [test]
Data Handler --> [test]
-- (len: 28)
Data         --> [test] [test] [test] [test]
Data Handler --> [test]
-- (len: 35)
Data         --> [test] [test] [test] [test] [test]
Data Handler --> [test]
-- (len: 42)
Data         --> [test] [test] [test] [test] [test] [test]
Data Handler --> [test]
-- (len: 49)
Data         --> [test] [test] [test] [test] [test] [test] [test]
Data Handler --> [test]
-- (len: 56)
Data         --> [test] [test] [test] [test] [test] [test] [test] [test]
Data Handler --> [test]
-- (len: 63)
Data         --> [test] [test] [test] [test] [test] [test] [test] [test] [test]
Data Handler --> [test]
-- (len: 70)
Data         --> [test] [test] [test] [test] [test] [test] [test] [test] [test] [test]
Data Handler --> [test]

内存使用/错误检查

在任何动态分配内存的代码中,对于分配的任何内存块,您都有2个职责:(1)始终保留指向起始地址的指针内存块,(2)当不再需要时,它可以释放

必须使用内存错误检查程序,以确保您没有在已分配的内存块之外/之外写入,尝试读取或基于未初始化的值跳转,最后确认您已释放所有内存你分配的记忆。对于Linux valgrind是正常的选择。它使用简单。

$ valgrind ./bin/snprintfnoinit
==25279== Memcheck, a memory error detector
==25279== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==25279== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==25279== Command: ./bin/snprintfnoinit
==25279==
7 --> req
-- (len: 7)
Data         --> [test]
Data Handler --> [test]
-- (len: 14)
...
==25279==
==25279== HEAP SUMMARY:
==25279==     in use at exit: 0 bytes in 0 blocks
==25279==   total heap usage: 10 allocs, 10 frees, 395 bytes allocated
==25279==
==25279== All heap blocks were freed -- no leaks are possible
==25279==
==25279== For counts of detected and suppressed errors, rerun with: -v
==25279== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)

始终确认释放所有堆块 - 不可能泄漏并且同样重要错误摘要:0个上下文中的0个错误

查看代码的更改,如果您有任何问题,请告诉我。

答案 2 :(得分:0)

将这个include添加到代码中以使其编译:

#include <stdio.h>

编译器提供有关代码未按预期工作的原因的提示:

Microsoft (R) C/C++ Optimizing Compiler Version 19.00.23506 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

test.c
d:\temp\test.c(16) : warning C4700: uninitialized local variable 'data' used
d:\temp\test.c(24) : warning C4700: uninitialized local variable 'len' used

修改

下面是你的代码添加了一个包含文件,以便编译并通过编译器建议的启动变量来修复警告:

#include <stdio.h>

int main() {

char    *data=0;
char    *data_handler;
int      i = 0;
int      len=0, req;
char     test[10] = "test";

for(; i<10; i++){

    req = snprintf(NULL, 0 , "[%s] ", test);

    printf("%d --> req \n", req);
    if (data == NULL) {
        data = (char *) malloc ((sizeof(char) * req) + 1);
        data_handler = data;
    } else {
        data_handler = data + len;
        data_handler = (char *) malloc ((sizeof(char) * req) +1);
    }

    len += snprintf(data_handler, sizeof(data) , "[%s] ", test);

    printf("\nData --> %s\n", data);
    printf("\nData Handler --> %s\n", data_handler);
}

printf ("%s", data);

}

以下是该代码产生的输出:

7 --> req 

Data --> [te

Data Handler --> [te
7 --> req 

Data --> [te

Data Handler --> [te
7 --> req 

Data --> [te

Data Handler --> [te
7 --> req 

Data --> [te

Data Handler --> [te
7 --> req 

Data --> [te

Data Handler --> [te
7 --> req 

Data --> [te

Data Handler --> [te
7 --> req 

Data --> [te

Data Handler --> [te
7 --> req 

Data --> [te

Data Handler --> [te
7 --> req 

Data --> [te

Data Handler --> [te
7 --> req 

Data --> [te

Data Handler --> [te
[te