2013-07-31 2 views
0

[EDIT] вставляется NULL, завершается в образцахva_list и символьные строки *

У меня есть функция, которая принимает va_list, который заканчивается с NULL. Я объединяю каждую строку в char* под названием joinedString. Функция работает, как ожидалось, за исключением того, что мой joinedString растет каждый раз, когда я вызываю эту функцию. Я имею в виду, что предыдущая строка остается и новая строка соединена.

Пример: Первый вызов:

ShowMsg(style1, "a", "s", "d", NULL); 

Поддавшись Результат: "ASD"

Второй вызов:

ShowMsg(style1, "w", "w", "q", NULL); 

Поддавшись Результат: "asdwwq"

Такое поведение является странно, потому что каждый раз, когда эта функция называется joinedString инициализируется. Использует ли va_list ранее используемые значения? Я использую C, а не C++, и я знаю, что использование std :: string будет намного проще.

int ShowMsg(MSGBOXSTYLE msgStyle, char* str, ...) 
{ 
    char* title = "", *joinedString = "", *theArg = ""; 
    wchar_t* convertedTitle = "", *convertedString = ""; 

    va_list args; 
    theArg = str; 
    va_start(args, str); 
     while(theArg != NULL) 
     { 
      if(msgStyle == WARN) 
      { 
       title = theArg; 
      } 
      else 
      { 
       strcat(joinedString, theArg); 
       strcat(joinedString, "\n\r"); 
      } 
      theArg = va_arg(args, char*); 
     } 
    va_end(args); 
    ... 
    convertedTitle = (wchar_t*)malloc((strlen(title)+1)*sizeof(wchar_t)); 
    convertedString = (wchar_t*)malloc((strlen(joinedString)+1)*sizeof(wchar_t)); 
    mbstowcs(convertedTitle, title, strlen(title)+1); 
    mbstowcs(convertedString, joinedString, strlen(joinedString)+1); 
    ... 
    free(convertedTitle); 
    free(convertedString); 
} 
+1

«Такое поведение является странным, потому что каждый раз, когда эта функция вызывается joinString инициализируется «всегда инициализируется указателем на ту же строку (« »), и вы изменяете ее после того, как это небезопасно. Используйте malloc для выделения памяти для char * vars. – ShPavel

+0

Ваш 'strcat (joinString ...' выглядит очень подозрительно для меня. Сколько пространства присваивается joinString? Это похоже на один байт для меня. –

+1

Другая проблема: в ваших образцах вы не заканчиваете список параметров с помощью NULL, это должно быть «ShowMsg (style1,« a »,« s »,« d », NULL); –

ответ

2

Это потому, что вы не можете инициализировать такие строки. Ваш инициализатор char* joinedString = "" инициализирует указатель joinedString, чтобы указать на определенный адрес памяти, который находится в начале вашей программы, состоит из пустой строки.

Тогда при первом вызове функции joinedString настроен на то, что все еще пустая область памяти. Затем вы помещаете туда несколько символов и выходите.

В следующий раз, когда вы начнете, персонажи все еще там. Единственное, что вы инициализируете, это указатель, а не фактические данные. strcat затем добавляет ваши новые аргументы в конец уже заполненной строки!

Это должно быть segfault, я действительно впечатлен тем, что ваша программа выводит НИЧЕГО. Вероятно, это работает только потому, что вы используете только несколько байтов, поэтому вы не слишком сильно переписываете.

Чтобы исправить это, инициализируется joinedString с таНосом:

char* joinedString = malloc(MAX_LENGTH * sizeof(*joinedString)); 
joinedString[0] = '\0'; // Initialize to an empty string 

А потом в конце вашей функции, свободный, что память

free(joinedString); 
+0

Вам также нужно отслеживать длину joinString - вы установите максимальную длину в вызове' malloc', а затем вам нужно будет отслеживать максимальную длину. Используйте 'strncat', чтобы вы никогда не превышали выделенную длину строки. – Dan

+0

Точно Dan. Мое намерение состоит в том, чтобы получить переменную char *. Выделение этой функции в отдельной программе происходит сбой. Создание ваших предложений. Но, как я уже сказал, мое намерение состоит в том, чтобы получить все строки, которые могут быть переданы, и присоединиться к ним в этом указателе символов. Из-за этого я не определил фиксированный размер для char и выделил его. Это чистый способ сделать переменную char *? – learner

+1

Для простоты вы должны определить НЕКОТОРЫЕ максимальные длины. Вы МОЖЕТЕ динамически вычислять это на основе длины входов, но для этого потребуется вторая петля через ваши varargs. Просто определите новый 'int len ​​= 0', добавьте длины всех аргументов и добавьте 3 (для конечного' '\ r \ n \ 0" '), затем вызовите' malloc' на основе этой переменной. Как я уже сказал, вы не можете сделать это «на лету», вам нужно пройти через аргументы, чтобы получить каждую длину, затем нажмите «malloc», THEN снова прокрутите аргументы, чтобы на самом деле «strcpy» их. – Dan

2

char *joinedString = "" означает joinedString указывает на массив символов только для чтения, 1 байт.

Нельзя записывать в этот раздел памяти. Он будет разбиваться на многие системы. Кроме того, даже если вы можете, когда вы пишете за конец массива с strcat(joinedString, theArg);, вы вызываете неопределенное поведение.

+0

Мое намерение состоит в том, чтобы получить динамический символ *. Для меня это и использование strcat char * будет динамическим. – learner

+1

@learner, но это не динамический. 'Char * joinString =" "' объявляет 'joinString' как указатель- to-char, и инициализирует его, указывая на однобайтную область памяти, то есть вам не разрешено изменять. Случайное записывание в память, которая не принадлежит вам, не является динамической, за исключением того, что «удерживает заголовок k динамита ", может быть. –

+1

Если вам нужен динамически изменяемый блок памяти, выделите его с помощью функции ['malloc()') (http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html), динамически измените ее размер ['realloc()'] (http://pubs.opengroup.org/onlinepubs/9699919799/functions/realloc.html), и когда вы закончите, отпустите его с помощью ['free()'] (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html). Не забывайте проверять 'malloc()' возвращающий NULL и не забывать о том, чтобы удалить указатель, который вы передаете 'realloc()', потому что 'realloc()' также может возвращать NULL. –