Ошибка при попытке добавить две строки с помощью snprintf - PullRequest
2 голосов
/ 20 июля 2009

Я пытаюсь добавить две строки с 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 - строки, определенные в заголовке. Иногда этот код работает, иногда нет. Я уверен, что это какая-то проблема с памятью, что я сделал не так?

EDIT: По какой-то причине я думал, что snprintf выделил вам память. Я принимаю ответ, который прояснил это, поскольку это была моя настоящая проблема, но я решил пойти на конкатенацию строк времени компиляции, так как это действительно хороший трюк.

Ответы [ 7 ]

5 голосов
/ 20 июля 2009

Если 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));
}
4 голосов
/ 20 июля 2009

Сначала вы должны выделить память.

char * filename = NULL;
filename = malloc(sizeof(PATH) + sizeof(FILE) + 1);
snprintf (filename, sizeof(PATH) + sizeof(FILE) + 1, "%s/%s", PATH, FILE);
2 голосов
/ 20 июля 2009

Вы знаете длину строки во время компиляции, поэтому нет необходимости в динамическом размещении.

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)
0 голосов
/ 21 июля 2009

В некоторых системах вы можете использовать asprintf:

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

Насколько я знаю, asprintf - это изобретение Glibc , но оказалось настолько полезным, что некоторые другие libc также его реализовали.

0 голосов
/ 20 июля 2009

В вашем коде есть несколько проблем:

  • вы объявляете указатель, char * filename без выделения памяти для него.

    1. использование sizeof () для указателей (на char *) действительно опасно:

</p> <pre><code>char hello[] = "world"; /* yield 6 */ char *hello2 = hello; /* yield 4 or 8 */

поэтому вы должны сначала выделить достаточно памяти для хранения имени файла:

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);

в качестве альтернативы вы можете просто выделить большой массив символов:

char filename[1024]; // or #define a MAXPATH lenght
snprintf(filename, filesize, "%s/%s", FILE, PATH);
/* hoping that filename lenght is less than 1024 or MAXPATH... */      
0 голосов
/ 20 июля 2009

Я бы просто добавил это как комментарий к ответу GMan, но пока они не объединили мою учетную запись, у меня не было представителя, чтобы сделать это. (И теперь ответ GMan, по-видимому, был удален, так что это имеет меньше смысла.)

Я думаю, что GMan имел в виду

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

чтобы получить длину этих констант, а не размер указателей, как указывает скользящий тулл. (Отредактировано: или, если sizeof (STRINGLITERAL) дает размер данных, включая завершающий ноль, то код GMan по-прежнему будет работать для строковых констант.)

Хотя, я думаю, что если вы знаете точные длины PATH и FILE (как bufferSize), вам не нужен snprintf (), просто sprintf () будет безопасным. Но использование snprintf () не причинит вреда, так как вам все равно нужен bufferSize для выделения.

Отредактировано: Или, у Эндрю Y может быть даже лучший подход (для строковых констант времени компиляции), если это применимо к вам.

0 голосов
/ 20 июля 2009

Добавьте этот код:

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

УСТАНОВИТЬ LEN на некоторое значение> = ПУТЬ и ФАЙЛ. Не забудьте освободить место, когда закончите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...