试图用snprintf添加两个字符串的Bug

时间:2009-07-20 19:11:47

标签: c string memory-management

我正在尝试用snprintf添加两个字符串,但显然我不知道我在做什么。

以下是代码块:

char * filename = NULL;

(void)snprintf (filename, sizeof(filename), "%s/%s",
        PATH, FILE);  

我也尝试过:

char * filename = NULL;

(void)snprintf (filename, sizeof(PATH)+sizeof(FILE)+1, "%s/%s",
        PATH, FILE);  

PATH和FILE是标头定义的字符串。有时,这段代码有效,偶尔也没有。我确定这是某种记忆问题,我做错了什么?

编辑: 我的问题是出于某种原因认为snprintf为你分配了内存。我接受了解决这个问题的答案,因为这是我真正的问题,但我决定使用编译时字符串连接,因为这是一个非常好的技巧。

7 个答案:

答案 0 :(得分:5)

如果FILE和PATH在头文件中定义为字符串文字,那么你可以在编译时连接:

#include <stdio.h>
/* elsewhere in your headers */
#define FILE "foo.ext"
#define PATH "/dir/subdir"

/* After including those headers */
#define FULLPATH (PATH "/" FILE)

int main(int argc, char *argv[]) {
  printf("%s\n", FULLPATH);
}

或者在声明变量时直接执行此操作并在代码中的其他地方引用它:

#include <stdio.h>

#define FILE "foo.ext"
#define PATH "/dir/subdir"

char fullpath[] = PATH "/" FILE;

int main(int argc, char *argv[]) {
  printf("%s occupies %d bytes\n", fullpath, sizeof(fullpath));
}

答案 1 :(得分:4)

你应该先分配内存。

char * filename = NULL;
filename = malloc(sizeof(PATH) + sizeof(FILE) + 1);
snprintf (filename, sizeof(PATH) + sizeof(FILE) + 1, "%s/%s", PATH, FILE);

答案 2 :(得分:2)

您知道编译时字符串的长度,因此不需要动态分配。

static char filename[sizeof(PATH) + sizeof(FILE)];
snprintf(filename, sizeof(filename), "%s/%s", PATH, FILE);

但是,由于您想要加入的字符串很可能是以文字形式提供的,因此根本不需要snprintf()

static const char filename[] = PATH "/" FILE;

另外,因为字符串长度存在一些混淆:

strlen(PATH) + strlen("/") + strlen(FILE) + 1
= (sizeof(PATH)-1) + 1 + (sizeof(FILE)-1) + 1
= sizeof(PATH) + sizeof(FILE)

答案 3 :(得分:0)

添加此代码:

if (!(filename = malloc((LEN + 1) * sizeof(char))))
        return 1;

将LEN设置为某个值&gt; = PATH和FILE长度。完成后不要忘记解除分配。

答案 4 :(得分:0)

我只是将此作为对GMan答案的评论添加,但在他们合并我的帐户之前,我没有代表这样做。 (而且现在GMan的答案显然已被删除,所以这没有多大意义。)

我认为GMan意味着

unsigned bufferSize = strlen(PATH) + strlen(FILE) + 2; // "/" and null-terminator

获取这些常量的长度,而不是指针的大小,如滑点指出的那样。 (编辑:或者,如果sizeof(STRINGLITERAL)给出数据的大小,包括结尾的null,那么对于字符串常量,GMan的代码仍然可以工作。)

虽然,我想如果你知道PATH和FILE的确切长度(作为bufferSize)你不应该需要snprintf(),只需sprintf()就可以了。但是使用snprintf()没有任何害处,因为无论如何你需要bufferSize进行分配。

编辑:或者,Andrew Y可能有更好的方法(对于编译时字符串常量),如果它可以适用于你。

答案 5 :(得分:0)

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

  • 你正在声明一个指针,char * filename而没有为它分配内存。

    1. 使用sizeof()作为指针(对于char *)是非常危险的:

char hello[] = "world";  /* yield 6 */
char *hello2 = hello;    /* yield 4 or 8 */

char hello[] = "world"; /* yield 6 */ char *hello2 = hello; /* yield 4 or 8 */

所以你必须先分配足够的内存来保存文件名:

或者你可以只分配一大堆char:

size_t filesize = strlen(PATH) + strlen(FILE) + 2; /* \0 + / */
char *filename = malloc(filesize);

if (filename == NULL) {
     /* error handling */
}

/* now you can safely write to filename: */
snprintf(filename, filesize, "%s/%s", FILE, PATH);

答案 6 :(得分:0)

在某些系统上,您可以使用asprintf

char *filename = NULL;
asprintf(&filename, "%s/%s", PATH, FILE);

据我所知,asprintf是一项Glibc发明,但事实证明其他几个libc已经实现了它。