Как мне работать с массивами символов argv? - PullRequest
3 голосов
/ 31 июля 2009

Я нашел два способа передачи аргументов командной строки в массив символов:

int main (int argc, char **argv)
{
  const char *s1 = argv[0];
  char s2[256];
  strcpy(s2, argv[0]);

  printf("s1: %s\ns2: %s\n\n", s1, s2);
}

Скомпилировано с помощью компилятора IBM xlc в системе AIX Возвращает

[MyPrompt]> ./a.out

s1: ./a.out

с2: ./a.out

Какая реализация (s1 или s2) верна? s1 хорош, потому что argv [0] может быть любой длины. s2 требует, чтобы длина argv [0] <256 символов. </p>

Я не понимаю, как / почему s1 должен работать. Я думаю, правая часть s1 должна требоваться во время компиляции, но я думаю, что он генерируется во время выполнения.

Ответы [ 6 ]

3 голосов
/ 31 июля 2009

Если вы не хотите изменять строку, тогда s1 будет работать.

Если вы хотите изменить строку, вы можете сделать ее копию. Вы должны использовать безопасные функции strnlen () и strncpy (), если ваша система это поддерживает.

3 голосов
/ 31 июля 2009

Причина работы s1 в том, что тип argv [0] равен указателю. Вы просто назначаете адрес (не фактическое значение), что безопасно. Вы не выполняете никакого распределения или каста.

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

1 голос
/ 31 июля 2009

s2 обладает восхитительным свойством быть подверженным переполнению буфера.

Я видел, как люди меняли значение argv [0]. В некоторых случаях (в некоторых ОС) изменение argv [0] приведет к тому, что программа будет отображаться в ps как и все, что вы изменили.

1 голос
/ 31 июля 2009

Я думаю, что правая часть s1 должно потребоваться во время компиляции, но я думаю, что это генерируется в время выполнения.

Нет, это требуется каждый раз, когда встречается утверждение. Например:

void f() {
   int x = 1;
   ...
}

Целое число x будет инициализироваться в 1 при каждом вызове функции, а не во время компиляции.

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

Я бы пошел с s1, особенно для argv [n], где n> 0. Такие вещи, как s2, открывают вас для классических атак переполнения буфера. По сути, пользователь может отформатировать аргумент длиной более 256 символов и перезаписать информацию в стеке, чтобы он мог запускать любой код по своему усмотрению.

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

Если вы просто хотите сослаться на аргумент, не внося в него никаких изменений, то s1 является правильным.

Если вам нужно каким-либо образом изменить аргумент, вам нужно сделать его копию, как в примере s2 , но в примере s2 вам необходимо явно проверить, длина длиннее буфера, в который вы копируете его. Например, если вы берете аргумент наподобие filename.jpg в качестве входных данных и сохраняете filename.gif в качестве выходных данных, вам нужно сделать копию этого аргумента, поскольку вы будете изменять расширение с .jpg на .gif

...