2010-03-15 2 views
0

Моя функция передается структурой, содержащей, среди прочего, NULL завершенный массив указателей на слова, составляющие команду с аргументами.Как переписать массив указателей на символы с большим списком указателей на символы?

Я выполняю сопоставление glob в списке аргументов, чтобы развернуть их в полный список файлов, а затем я хочу заменить переданный массив аргументов новым расширенным.

Глобус работает нормально, то есть g.gl_pathv заполняется списком ожидаемых файлов. Однако мне трудно скопировать этот массив в структуру, которую я получил.

#include <glob.h> 

struct command { 
    char **argv; 
    // other fields... 
} 

void myFunction(struct command * cmd) 
{ 
    char **p = cmd->argv; 
    char* program = *p++; // save the program name (e.g 'ls', and increment to the first argument 

    glob_t g; 
    memset(&g, 0, sizeof(g)); 
    g.gl_offs = 1; 
    int res = glob(*p++, GLOB_DOOFFS, NULL, &g); 
    glob_handle_res(res); 
    while (*p) 
    { 
     res = glob(*p, GLOB_DOOFFS | GLOB_APPEND, NULL, &g); 
     glob_handle_res(res); 
    } 

    if(g.gl_pathc <= 0) 
    { 
     globfree(&g); 
    } 

    cmd->argv = malloc((g.gl_pathc + g.gl_offs) * sizeof *cmd->argv); 

    if (cmd->argv == NULL) { sys_fatal_error("pattern_expand: malloc failed\n");} 
    // copy over the arguments 
    size_t i = g.gl_offs; 
    for (; i < g.gl_pathc + g.gl_offs; ++i) 
     cmd->argv[i] = strdup(g.gl_pathv[i]); 

    // insert the original program name 
    cmd->argv[0] = strdup(program); 
    ** cmd->argv[g.gl_pathc + g.gl_offs] = 0; ** 
    globfree(&g); 
} 

void 
command_free(struct esh_command * cmd) 
{ 
    char ** p = cmd->argv; 
    while (*p) { 
     free(*p++); // Segfaults here, was it already freed? 
    } 
    free(cmd->argv); 
    free(cmd); 
} 

Edit 1: Кроме того, я понял, что нужно придерживаться программы обратно туда, как Cmd-> ARGV [0]
Edit 2: Добавлен вызов calloc
Редактировать 3: Изменить управление MEM с советами от Alok
Edit 4: Дополнительные советы от Alok
Edit 5: Почти работает .. приложение при освобождении ошибки сегментации команды-структуру

Наконец: Похоже, мне не хватало завершающего NULL, поэтому добавление строки:

cmd->argv[g.gl_pathc + g.gl_offs] = 0; 

, похоже, запустил его.

+0

Так оно работает сейчас? Если нет, то какая ошибка вы получаете? Также см. Мое последнее изменение в моем ответе. Вы выделяете пробел дважды для 'paths [0]', один раз с 'malloc', а затем снова с' strdup'. –

+0

да, этот код был жестоким .. см. Последнее редактирование. он по-прежнему сбой при доступе к новому массиву. Возможно, символы \ 0 теряются при перетасовке? – Casey

+0

В 'cmd-> argv [g.gl_pathc + g.gl_offs] = '\ 0';', '' \ 0'' эквивалентен '0', что эквивалентно здесь' NULL', поэтому вы должны используйте 'NULL' вместо' '\ 0''. –

ответ

1

argv представляет собой массив указателей char *. Это означает, что argv имеет место для argcchar * значений. Если вы попытаетесь скопировать больше, чем много значений char *, вы получите переполнение.

Скорее всего, ваши glob результаты вызова в более argc элементов в gl_pathv поле (т.е., gl_pathc > argc). Это неопределенное поведение.

Он похож на код ниже:

/* Wrong code */ 
#include <string.h> 

int a[] = { 1, 2, 3 }; 
int b[] = { 1, 2, 3, 4 }; 
memcpy(a, b, sizeof b); 

Решение: вы должны либо работать с glob_t STRUCT непосредственно, или выделить новое пространство для копирования gl_pathv на новый char **:

char **paths = malloc(g.gl_pathc * sizeof *paths); 
if (paths == NULL) { /* handle error */ } 
for (size_t i=0; i < g.gl_pathc; ++i) { 
    /* The following just copies the pointer */ 
    paths[i] = g.gl_pathv[i]; 

    /* If you actually want to copy the string, then 
     you need to malloc again here. 

     Something like: 

     paths[i] = malloc(strlen(g.gl_pathv[i] + 1)); 

     followed by strcpy. 
    */ 
} 

/* free all the allocated data when done */ 

Редактировать: после вашего редактирования:

cmd->argv = calloc(g.gl_pathc, sizeof(char *) *g.gl_pathc); 

он должен работать, но каждый из argv[1] до argv[g.gl_pathc + g.gl_offs - 1] является char *, который является «принадлежащим» struct glob. Ваш вызов memcpy только копирует указатели. Когда вы позже сделаете globfree(), эти указатели больше ничего не означают. Таким образом, вы должны сделать копию строки для использования:

size_t i; 
cmd->argv = malloc((g.gl_pathc+g.gl_offs) * sizeof *cmd->argv); 
for (i=g.gl_offs; i < g.gl_pathc + g.gl_offs; ++i) 
    cmd->argv[i] = strdup(g.gl_pathv[i]); 

Это гарантирует, что теперь у вас есть свои собственные копии строк. Обязательно освободите их (и argv), как только вы закончите.

Есть еще несколько проблем с вашим кодом.

  1. Вы делаете *p++, вы должны сделать p++, так как вы не используете значение разыменования.
  2. Вы должны действительно проверить возвращаемое значение glob.
  3. Ваш paths переменная нуждается в g.gl_pathc + 1 элементов, а не g.gl_pathc. (Или, вернее, вам нужно выделить g.gl_pathc + g.gl_offs раз sizeof *paths байт.)
  4. Ваш for цикл для копирования строк должен быть for (j=1; j < g.gl_pathc + g.gl_offs; ++j).
  5. Убедитесь, что ваша оболочка не расширяет ваш шар. I.e., позвоните по номеру ./a.out '*' вместо ./a.out *.
+0

Идея моей функции, передаваемой командой struct, заключается в том, что моя функция является обработчиком сортами, выполняющим некоторую операцию над командной строкой до ее выполнения. следовательно, мне нужно изменить значение argv в cmd. – Casey

+0

Но откуда взялся элемент 'argv'' cmd'? Если это массив, вы не можете просто сказать 'cmd-> argv = ...', что является незаконным в C. Это похоже на: 'int a [] = {1, 2};' follow ' a = malloc (...); '. –

+0

Ничего, мой мозг не был занят. Я «пропустил» определение 'struct cmd'. –

0

Вам не нужно несколько g.gl_pathc по sizeof (char *)?

+0

hm, да .. но я думаю, что часть проблемы - cmd-> argv, вероятно, меньше g.gl_pathv. В конце концов, если исходный argv состоит из двух элементов: «ls» и «* .h» .. * .h может быть расшифрован на 100s имен файлов – Casey

+0

хорошая точка. Я просто заметил низко висящую ошибку. – bmargulies