Я должен использовать символ ** argv или символ* argv [] в C?

Rails позволяет указать, как должен выглядеть URL-адрес маршрутизации:

https://guides.rubyonrails.org/routing.html#translated-paths

122
задан Kredns 16 February 2010 в 00:32
поделиться

8 ответов

Поскольку вы только изучаете C, я рекомендую вам действительно постараться сначала понять различия между массивами и указателями вместо общих вещей .

В области параметров и массивов есть несколько запутанных правил, которые должны быть ясны перед тем, как продолжить. Во-первых, то, что вы объявляете в списке параметров, обрабатывается специальным образом. Существуют такие ситуации, когда вещи не имеют смысла в качестве параметра функции в C. Это

  • Функции в качестве параметров
  • Массивы в качестве параметров

Массивы в качестве параметров

Второе, возможно, не сразу понятно. Но это становится ясным, если учесть, что размер измерения массива является частью типа в C (а массив, размер измерения которого не указан, имеет неполный тип). Так, если бы вы создали функцию, которая принимает массив по значению (получает копию), то она могла бы сделать это только для одного размера! Кроме того, массивы могут стать большими, и C пытается быть максимально быстрым.

В C по этим причинам значений массивов не существует. Если вы хотите получить значение массива, вместо этого вы получите указатель на первый элемент этого массива. И в этом на самом деле уже лежит решение. Вместо того, чтобы рисовать неверный параметр массива, компилятор C преобразует тип соответствующего параметра в указатель. Запомните это, это очень важно. Параметр не будет массивом, а будет указателем на соответствующий тип элемента.

Теперь, если вы попытаетесь передать массив, то вместо этого передается указатель на первый элемент массива.

Экскурсия: Функции как параметры

Для завершения, и, поскольку я думаю, что это поможет вам лучше понять суть вопроса, давайте посмотрим, как обстоят дела, когда вы пытаетесь использовать функцию в качестве параметра. Действительно, во-первых, это не имеет никакого смысла. Как параметр может быть функцией? Да, мы хотим переменную в этом месте, конечно! Поэтому компилятор, когда это происходит, снова превращает функцию в указатель функции . Попытка передать функцию передаст указатель на соответствующую функцию. Итак, то же самое (аналогично примеру с массивом):

void f(void g(void));
void f(void (*g)(void));

Обратите внимание, что скобки вокруг * g необходимы. В противном случае он указывал бы функцию, возвращающую void * , вместо указателя на функцию, возвращающую void .

Назад к массивам

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

int main(int c, char **argv);
int main(int c, char *argv[]);
int main(int c, char *argv[1]);
int main(int c, char *argv[42]);

Конечно, нет смысла помещать в него какой-либо размер, и он просто отбрасывается. По этой причине C99 придумал новое значение для этих чисел и позволяет другим вещам появляться в скобках:

// says: argv is a non-null pointer pointing to at least 5 char*'s
// allows CPU to pre-load some memory. 
int main(int c, char *argv[static 5]);

// says: argv is a constant pointer pointing to a char*
int main(int c, char *argv[const]);

// says the same as the previous one
int main(int c, char ** const argv);

Последние две строки говорят, что вы не сможете изменить «argv» внутри функции - это стал константным указателем. Только немногие компиляторы C поддерживают эти функции C99. Но эти особенности дают понять, что «массив» не т на самом деле один. Это указатель.

Слово предупреждения.

Обратите внимание, что все, что я сказал выше, верно только в том случае, если вы получили массив в качестве параметра функции. Если вы работаете с локальными массивами, массив не будет указателем. Он будет вести себя как как указатель, потому что, как объяснено ранее, массив будет преобразован в указатель при чтении его значения. Но это не следует путать с указателями.

Одним из классических примеров является следующее:

char c[10]; 
char **c = &c; // does not work.

typedef char array[10];
array *pc = &c; // *does* work.

// same without typedef. Parens needed, because [...] has 
// higher precedence than '*'. Analogous to the function example above.
char (*array)[10] = &c;
158
ответ дан 24 November 2019 в 01:25
поделиться

You could use either, it depends how you want to use it. char* argv[] is (mostly) equivalent to char ** argv. Both forms are pointer to pointers to char, the only difference is that with char *argv[] you are informing the compiler that the value of argv won't change (though the values it points to still can). Actually, I'm wrong, they're completely equivalent. See litb's comments and his answer.

It really depends how you want to use it (and you could use either in any case):

// echo-with-pointer-arithmetic.c
#include <stdio.h>
int main(int argc, char **argv)
{
  while (--argc > 0)
  {
    printf("%s ", *++argv);
  }
  printf("\n");
  return 0;
}

// echo-without-pointer-arithmetic.c
#include <stdio.h>
int main(int argc, char *argv[])
{
  int i;
  for (i=1; i<argc; i++)
  {
    printf("%s ", argv[i]);
  }
  printf("\n");
  return 0;
}

As for which is more common - it doesn't matter. Any experienced C programmer reading your code will see both as interchangeable (under the right conditions). Just like an experienced English speaker reads "they're" and "they are" equally easily.

More important is that you learn to read them and recognize how similar they are. You'll be reading more code than you write, and you'll need to be equally comfortable with both.

12
ответ дан 24 November 2019 в 01:25
поделиться

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

4
ответ дан 24 November 2019 в 01:25
поделиться

char ** → указатель на символьный указатель, а char * argv [] означает массив символьных указателей. Поскольку мы можем использовать указатель вместо массива, можно использовать оба.

1
ответ дан 24 November 2019 в 01:25
поделиться

Если вам нужно переменное или динамическое количество строк, используйте символ ** может быть проще работать. Если число строк фиксировано, то будет предпочтительнее char * var [].

-2
ответ дан 24 November 2019 в 01:25
поделиться

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

0
ответ дан 24 November 2019 в 01:25
поделиться

Это не имеет значения, но я использую char * argv [] , потому что это показывает, что это массив фиксированной длины строк переменной длины (обычно это char * ).

8
ответ дан 24 November 2019 в 01:25
поделиться

Вы можете использовать любую из двух форм, так как в C массивы и указатели взаимозаменяемы в списках параметров функции. См. http://en.wikipedia.org/wiki/C_ (software_language) # Array-pointer_interchangeability .

9
ответ дан 24 November 2019 в 01:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: