Передача указателей массивов в C - PullRequest
7 голосов
/ 02 февраля 2009

Итак, у меня есть код, который выглядит следующим образом:

int a[10];
a = arrayGen(a,9);

и функция arrayGen выглядит следующим образом:

int* arrayGen(int arrAddr[], int maxNum)
{
    int counter=0;
    while(arrAddr[counter] != '\0') {
        arrAddr[counter] = gen(maxNum);
        counter++;
    }
    return arrAddr;
}

Сейчас компилятор сообщает мне «предупреждение: передача аргумента 1 из« arrayGen »делает целое число из указателя без приведения»

Я думаю, что я передаю 'a', указатель на [0], тогда, так как массив уже создан, я могу просто заполнить значения для [n], пока I a [n] == '\ 0 ». Я думаю, что моя ошибка в том, что arrayGen написан так, чтобы принимать массив, а не указатель на него. Если это правда, я не уверен, как поступить, записывать ли значения в адреса, пока содержимое одного адреса не будет равно «\ 0»?

Ответы [ 7 ]

17 голосов
/ 02 февраля 2009

Основная магия здесь - это тождество в C:

*(a+i) == a[i]

Хорошо, теперь я сделаю так, чтобы этот текст читался на английском.

Вот проблема: имя массива не является lvalue; это не может быть назначено. Таким образом, линия у вас есть с

a = arrayGen(...)

это проблема. Смотрите этот пример:

int main() {
    int a[10];

    a = arrayGen(a,9);

    return 0;
}

, что дает ошибку компиляции:

gcc -o foo foo.c
foo.c: In function 'main':
foo.c:21: error: incompatible types in assignment

Compilation exited abnormally with code 1 at Sun Feb  1 20:05:37

Вам нужно иметь указатель, который равен lvalue, для которого можно назначить результаты.

Этот код, например:

int main() {
    int a[10];
    int * ip;

    /* a = arrayGen(a,9);  */
    ip = a ; /* or &a[0] */
    ip = arrayGen(ip,9);

    return 0;
}

отлично компилируется:

gcc -o foo foo.c

Compilation finished at Sun Feb  1 20:09:28

Обратите внимание, что из-за идентификатора вверху вы можете обрабатывать ip как массив, если хотите, как в этом коде:

int main() {
    int a[10];
    int * ip;
    int ix ;

    /* a = arrayGen(a,9);  */
    ip = a ; /* or &a[0] */
    ip = arrayGen(ip,9);

    for(ix=0; ix < 9; ix++)
        ip[ix] = 42 ;

    return 0;
}

Полный пример кода

Просто для полноты вот мой полный пример:

int gen(int max){
    return 42;
}

int* arrayGen(int arrAddr[], int maxNum)
{
    int counter=0;
    while(arrAddr[counter] != '\0') {
        arrAddr[counter] = gen(maxNum);
        counter++;
    }
    return arrAddr;
}

int main() {
    int a[10];
    int * ip;
    int ix ;

    /* a = arrayGen(a,9);  */
    ip = a ; /* or &a[0] */
    ip = arrayGen(ip,9);

    for(ix=0; ix < 9; ix++)
        ip[ix] = 42 ;

    return 0;
}
4 голосов
/ 02 февраля 2009

Зачем даже возвращать arrAddr? Вы передаете [10] по ссылке, чтобы содержимое массива было изменено. Если вам не нужна другая ссылка на массив, тогда предложение charlies правильное.

2 голосов
/ 02 февраля 2009

Я не уверен, что вы пытаетесь сделать, но присваивание значения указателя массиву беспокоит компилятор, как упомянуто Чарли . Мне любопытно проверить соответствие символьной константы NUL '\0'. Ваш образец массива является неинициализированной памятью, поэтому сравнение в arrayGen не даст того, что вы хотите.

Список параметров, который вы используете, в конечном итоге будет идентичен:

int* arrayGen(int *arrAddr, int maxNum)

для большинства целей. Фактическое утверждение в стандарте:

Объявление параметра как «массива тип » должно быть скорректировано на «квалифицированный указатель на тип », где квалификаторы типа (если таковые имеются) - те, которые указаны в [и] из производного типа массива. Если ключевое слово static также присутствует в [и] деривации типа массива, то при каждом вызове функции значение соответствующего фактического аргумента должно обеспечивать доступ к первому элементу массива как минимум с таким количеством элементов, которое указано в выражении размера.

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

void accepts_pointer_to_array (int (*ary)[10]) {
    int i;
    for (i=0; i<10; ++i) {
        (*ary)[i] = 0; /* note the funky syntax is necessary */
    }
}

void some_caller (void) {
    int ary1[10];
    int ary2[20];
    int *ptr = &ary1[0];
    accepts_pointer_to_array(&ary1); /* passing address is necessary */
    accepts_pointer_to_array(&ary2); /* fails */
    accepts_pointer_to_array(ptr);   /* also fails */
}

Ваш компилятор должен жаловаться, если вы вызываете его с чем-либо, что не является указателем на массив из 10 целых чисел. Хотя я могу честно сказать, что я никогда не видел эту книгу за пределами различных книг ( The C Book , Expert C Programming ) ... по крайней мере, не в программировании на C. Однако в C ++ у меня была причина использовать этот синтаксис ровно в одном случае:

template <typename T, std::size_t N>
std::size_t array_size (T (&ary)[N]) {
    return N;
}

Ваш пробег может отличаться. Если вы действительно хотите углубиться в подобные вещи, я не могу рекомендовать Программирование на Expert C достаточно высоко. Вы также можете найти The C Book онлайн на gbdirect .

2 голосов
/ 02 февраля 2009

Хм, я знаю, что на ваш вопрос ответили, но что-то еще в коде беспокоит меня. Почему вы используете тест против '\ 0', чтобы определить конец массива? Я уверен, что это работает только со строками C. Код действительно компилируется после предложенного исправления, но если вы перебираете свой массив, мне интересно посмотреть, получаете ли вы правильные значения.

0 голосов
/ 02 февраля 2009

@ jeffD Прохождение индекса было бы предпочтительным способом, так как нет никакой гарантии, что вы не достигнете других '\ 0' до вашего последнего (я определенно был, когда проверял его).

0 голосов
/ 02 февраля 2009

То, как вы используете это arrayGen (), не нужно возвращать значение. Вам также нужно поместить '\ 0' в последний элемент, это не будет сделано автоматически, или передать индекс последнего элемента для заполнения.

0 голосов
/ 02 февраля 2009

Попробуйте вызвать ваш параметр int* arrAddr, а не int arrAddr[]. Хотя, когда я думаю об этом, параметры для метода main похожи, но он работает. Так что не уверен насчет объяснения.

Редактировать: Хм, все ресурсы, которые я могу найти в интернете, говорят, что это должно работать. Я не уверен, я всегда передавал массивы как указатели сам, поэтому никогда не сталкивался с этой ошибкой, поэтому я очень заинтересован в решении.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...