Rails позволяет указать, как должен выглядеть URL-адрес маршрутизации:
https://guides.rubyonrails.org/routing.html#translated-paths
Поскольку вы только изучаете 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;
You could use either, it depends how you want to use it. Actually, I'm wrong, they're completely equivalent. See litb's comments and his answer.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).
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.
На самом деле это не имеет значения, но последний более читабелен. Вам дают массив указателей на символы, как говорит вторая версия. Однако он может быть неявно преобразован в указатель с двумя символами, как в первой версии.
char ** → указатель на символьный указатель, а char * argv [] означает массив символьных указателей. Поскольку мы можем использовать указатель вместо массива, можно использовать оба.
Если вам нужно переменное или динамическое количество строк, используйте символ ** может быть проще работать. Если число строк фиксировано, то будет предпочтительнее char * var [].
Я не вижу особой пользы в том, чтобы использовать один из подходов вместо другого - использовать соглашение, наиболее соответствующее остальному вашему коду.
Это не имеет значения, но я использую char * argv []
, потому что это показывает, что это массив фиксированной длины строк переменной длины (обычно это char *
).
Вы можете использовать любую из двух форм, так как в C массивы и указатели взаимозаменяемы в списках параметров функции. См. http://en.wikipedia.org/wiki/C_ (software_language) # Array-pointer_interchangeability .