Подтвердить что ты не робот

Разница между передающим массивом, массивом фиксированного размера и базовым адресом массива в качестве параметра функции

Я путаюсь, какой синтаксис использовать, если я хочу передать массив известного или неизвестного размера в качестве параметра функции.

Предположим, что у меня есть эти варианты для этой цели:

void func1(char* str) {
    //print str
}

void func2(char str[]) {
    //print str
}

void func3(char str[10]) {
    //print str
}

Каковы преимущества и недостатки использования каждого из них?

4b9b3361

Ответ 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.

Надеюсь, это поможет.