Разница между передающим массивом, массивом фиксированного размера и базовым адресом массива в качестве параметра функции
Я путаюсь, какой синтаксис использовать, если я хочу передать массив известного или неизвестного размера в качестве параметра функции.
Предположим, что у меня есть эти варианты для этой цели:
void func1(char* str) {
//print str
}
void func2(char str[]) {
//print str
}
void func3(char str[10]) {
//print str
}
Каковы преимущества и недостатки использования каждого из них?
Ответы
Ответ 1
Все эти варианты одинаковы. C просто позволяет использовать альтернативные варианты написания, но даже последний вариант, явно аннотированный с размером массива, распадается на обычный указатель.
То есть даже с последней реализацией вы можете вызвать функцию с массивом любого размера:
void func3(char str[10]) { }
func("test"); // Works.
func("let try something longer"); // Not a single f*ck given.
Излишне говорить, что этого нельзя использовать: это может дать пользователю ложное чувство безопасности ( "о, эта функция принимает только массив длиной 10, поэтому мне не нужно самому проверять длину" ).
Как сказал Хенрик, правильным способом в С++ является использование std::string
, std::string&
или std::string const&
(в зависимости от того, нужно ли изменять объект и хотите ли вы его копировать).
Ответ 2
Обратите внимание, что в С++, если длина массива известна во время компиляции (например, если вы передали строковый литерал), вы можете получить ее размер:
template<unsigned int N>
void func(const char(&str)[N])
{
// Whatever...
}
int main()
{
func("test"); // Works, N is 5
}
Ответ 3
В С++ используйте void func4(const std::string& str)
.
Ответ 4
Все они функционально идентичны. Когда вы передаете массив функции в C, массив получает неявное преобразование в указатель на первый элемент массива. Следовательно, эти три функции будут печатать тот же результат (то есть размер указателя на char
).
void func1(char* str) {
printf("sizeof str: %zu\n", sizeof str);
}
void func2(char str[]) {
printf("sizeof str: %zu\n", sizeof str);
}
void func3(char str[10]) {
printf("sizeof str: %zu\n", sizeof str);
}
Это преобразование применяется только к первому размеру массива. A char[42][13]
преобразуется в char (*)[13]
, а не в char **
.
void func4(char (*str_array)[13]) {
printf("sizeof str_array: %zu\n"
"sizeof str_array[0]: %zu\n", sizeof str_array, sizeof str_array[0]);
}
char (*)[13]
- тип str_array
. Это то, как вы пишете "указатель на массив из 13 char
s". Это также можно было бы записать как void func4(char str_array[42][13]) { ... }
, хотя 42 функционально бессмысленно, как вы можете видеть, экспериментируя, передавая массивы разного размера в func4
.
В C99 и C11 (но не C89 или С++) вы можете передать указатель на массив разного размера в функцию, передав его размер вместе с ним и включив идентификатор размера в [square brackets]
. Например:
void func5(size_t size, char (*str_array)[size]) {
printf("sizeof str_array: %zu\n"
"sizeof str_array[0]: %zu\n", sizeof str_array, sizeof str_array[0]);
}
Это объявляет указатель на массив размером char
s. Обратите внимание, что перед доступом к массиву вы должны разыменовать указатель. В приведенном выше примере sizeof str_array[0]
оценивается размер массива, а не размер первого элемента. В качестве примера, чтобы получить доступ к 11-му элементу, используйте (*str_array)[11]
или str_array[0][11]
.
Ответ 5
В C первые два определения эквивалентны. Третий по существу тот же, но он дает представление о размере массива.
Если печать str
является вашей целью, тогда вы можете безопасно использовать любой из них. По сути, всем трем функциям передается параметр типа char*
, а именно, что printf()
должен печатать строку. И не нужно вы не знаете, несмотря на то, что может показаться, все параметры, проходящие в C, выполняются в режиме pass-by-value
.
Изменить: Похоже, я буду очень строгим в выборе слов на SO впредь. Ну, в третьем случае он не представляет представления о размере массива к функции, к которой она передана, поскольку она в конечном итоге сводится к типу char*
точно так же, как и в первых двух случаях. Я хотел сказать, что это говорит человеку, читающему его, что размер массива равен 10. Также, это не неправильно/незаконно в C.But для программы, делая это так же хорошо, как бесполезно. Это не дает никакого представления о размере массива для функции, которую она передала .Mr.Downvoter, спасибо, указав, что случайное отношение и халатность не допускается на SO.
Ответ 6
В одномерном массиве все они обрабатываются компилятором одинаково. Однако для двух или более размерных массивов (например, myArray[10][10]
) это полезно, поскольку оно может использоваться для определения длины строки/столбца массива.
Ответ 7
Вложение, описывающее в точках.
1) Как все говорили, это одно и то же.
2) Массивы разлагаются в указатели, когда они передаются в аргументах функции.
3) Фундаментальной проблемой может быть поиск размера массива в функции. Для этого мы можем использовать макрос.
#define noOfElements(v) sizeof(v)/sizeof(0[v])
int arr[100]
myfunction ( arr, noOfElements(arr))
либо 0 [v], либо v [0] могут использоваться в макросе, где первый используется для того, чтобы избежать использования определенного пользователем типа данных в noOfElements.
Надеюсь, это поможет.