Ошибка сегментации при разборе va_args - PullRequest
2 голосов
/ 17 марта 2011

Почему код ниже дает EXC_BAD_ACCESS, could not access memory?

int combine_strings(char **outputStr,...)
{
    va_list ap;
    char *s, *out=0;
    int len=0;

    va_start(ap,outputStr);
    while(s=va_arg(ap,char *))
    {
      len+=strlen(s);
    }
    va_end(ap);


    if(!(out=malloc(len+1)))
        exit(1);

    *outputStr=out;

    va_start(ap,outputStr);
    while(s=va_arg(ap,char *))
    {
      len=strlen(s);
      memcpy(out,s,len);
      out+=len;
    }
    va_end(ap);

    *out=0;

    return 0;
}

Ответы [ 4 ]

8 голосов
/ 17 марта 2011

Я должен не согласиться с другими предыдущими постерами. Исходный код не повторяется один и тот же va_list дважды. Он создает два разных и по очереди перебирает каждый из них, хотя одна и та же переменная используется для хранения обоих списков.

На самом деле мне удалось правильно запустить функцию. Следовательно, я предполагаю, что проблема в том, как была вызвана функция. Вот как я это назвал, обратите внимание на конечный NULL и настройку параметра output:

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

// ... combine_strings() goes here...
int main()
{
  char * res;
  char * * output = &res;
  combine_strings(output, "FOO", "BAR", "BAZ", NULL);
  printf("%s\n", *output);
}

Приведенный выше код выводит FOOBARBAZ, как и ожидалось.

2 голосов
/ 17 марта 2011

Использование va_start дважды в одной функции трудно заставить работать на всех платформах.См. здесь для получения дополнительной информации.

Возможно, лучше всего использовать va_copy .

2 голосов
/ 17 марта 2011

Самый простой способ ответить на этот вопрос - запустить его в отладчике.Вы получите полную трассировку стека, указатель кода и сможете просматривать значения всех переменных.

Чтобы использовать gdb , сначала скомпилируйте программу с отладкой.символы (-g в gcc).Затем запустите его:

gdb program_name
(gdb) run

Произойдет сбой, и вы поймете, почему.

2 голосов
/ 17 марта 2011

Вы не можете повторять одно и то же va_list дважды.Вам необходимо создать копию, используя va_copy().

int combine_strings(char **outputStr,...)
{
    va_list ap, ap2;
    char *s, *out=0;
    int len=0;

    va_start(ap,outputStr);
    va_copy(ap2, ap);
    while(s=va_arg(ap2,char *))
    {
      len+=strlen(s);
    }
    va_end(ap2);


    if(!(out=malloc(len+1)))
        exit(1);

    *outputStr=out;

    while(s=va_arg(ap,char *))
    {
      len=strlen(s);
      memcpy(out,s,len);
      out+=len;
    }
    va_end(ap);

    *out=0;

    return 0;
}
...