2014-01-09 4 views
2

При написании небольших утилит UNIX на C я иногда хочу взять копию argv, предоставленную main(), чтобы я мог настроить параметры перед вызовом exec(). Ниже основывается на свободно реализации из xargs BSD (1):Есть ли простой способ скопировать argv в C?

void run_script(char *argv[]) { 
    char **tmp, **new_argv; 
    int argc; 

    for (argc=0; argv[argc] != 0; argc++); 
    new_argv = malloc((argc + 1) * sizeof(char *)); 
    for (tmp=new_argv; *argv != 0; tmp++) { 
     *tmp = *argv++; 
     *tmp = strdup(*tmp); 
    } 

    /* call execvp(3) using new_argv */ 

    for (i=0; i<=argc; i++) 
      free(new_argv[i]); 
    free(new_argv); 
} 

Это чувствует себя более сложным, чем это должно быть. Есть ли лучший способ написать это в C? (Возможно заполнение одного буфера, который был выделен с помощью _POSIX_ARG_MAX.)

+0

почему вы не передавая 'argc' из' функции main', слишком? так или иначе, потому что вы не можете надежно и безопасно определить размер массива с помощью указателя 'argv [argc]! = 0' означает, что вы определяете размер массива, явно просматривая память, которая выходит за пределы, надеясь, что это будет '0', почему бы просто не передать' argv' и назначить его локальному указателю, например GTK +? –

+2

@EliasVanOotegem: стандарт C гарантирует, что массив 'argv', переданный в' main', заканчивается нулевым указателем (и который вы можете проверить для этого нулевого указателя), поэтому здесь нет доступа к границам , –

+0

@BartvanIngenSchenau: Приятно знать ... в этом случае: 'argv [argc]! = 0' должно быть' argv [argc] ', никакого сравнения, чтобы оно не было' argv [argc]! = NULL' –

ответ

1

Я придумал другой процесс дублирования argv. Следующий пример не короче, но я думаю, что это легче читать:

void run_script(char *argv[]) { 
    int i; 
    char **new_argv; 
    char *p, *arg_buf; 
    int argc; 

    for (argc=0; argv[argc]; argc++); 
    arg_buf = malloc(ARG_MAX); 
    new_argv = calloc(argc+1, sizeof(char *)); 
    for (i=0, p=arg_buf; i<argc; i++) { 
      p += strlcpy(p, argv[i], ARG_MAX - (p - arg_buf)); 
      p++; 
    } 

    /* call execvp(3) using new_argv */ 

    free(arg_buf); 
    free(new_argv); 
} 

ARG_MAX На Linux должен быть заменен sysconf(_SC_ARG_MAX)

1

Мой C является немного ржавый, однако ....

В предположении, что ARGV [] собирается быть доступны в течение всего срока ваш скрипт, вам не нужны строки strdup, если они не будут изменены. После того, как вы выделите память (помните, чтобы добавить в argc больше, если вы хотите добавить дополнительные параметры), вы должны просто иметь возможность memcpy. Ваш new_argv будет указывать на те же строки, что и ваш исходный argv, поэтому вам нужно будет выполнить strdup, прежде чем изменять его (или нет, если вы хотите установить его в какую-либо другую строку).

Я думаю, вам нужно внимательно посмотреть на свою петлю, for (m=0, tmp.. - для начала я не думаю, что m используется где-либо еще; во-вторых, вы тестируете *argv != 0, но не меняете * argv в цикле, поэтому он будет работать вечно или вообще не будет, и, в-третьих, в начале этого цикла все ваши new_argv являются нулевыми указателями, поэтому *tmp = strdump(*tmp); попытается дублировать строка по адресу памяти 0, не имеющая ничего общего с argv?

+0

В этом случае я хочу скопировать argv, чтобы я может изменить один или несколько аргументов, прежде чем передавать их. Как выглядит вызов memcpy()? Я думаю, что это будет очень похоже на мое использование strdup(). Я добавил недостающую строку, которая увеличивает argv. – eradman

Смежные вопросы