Ошибка при доступе к двумерному массиву символов из функции в C

Я видел много онлайн-ресурсов о доступе к 2D-массиву в C, и все они показывают только один ответ *( *(arr + i) + j)) Но, к сожалению, это дало мне эту ошибку

error: invalid type argument of unary ‘*’ (have ‘int’)
 27 |      printf("%d ",*(*(arr + i) + j));

Мой код:

void pointer_string_array_indexing(char *arr){
        
        for (int i = 0; i < 2; ++i)
        {
            
            for (int j = 0; j < 4; ++j)
        {
            //printf("%c : %d ",*(arr+4*i+j),(arr+4*i+j)); //this will give correct answer
            printf("%c ",*( *(arr + i) + j)); // compilation error
        }
        printf("\n");
        }
        
    }

int main(){
    char S[][4] = {"abc","efg"};
    pointer_string_array_indexing(S);
return 0;

}

Я знаю, что это очень известный и повторяющийся вопрос, но, пожалуйста, предоставьте фрагмент кода решения. Я использую Ubuntu-20 (впрочем, это не имеет значения)

Пожалуйста, поделитесь некоторыми из этих «многих ресурсов» (чтобы мы могли показать вам, где вы неправильно их истолковываете). И поделитесь своей ошибкой.

JHBonarius 18.12.2020 17:10

@JHBonarius здесь я даю 2 ссылки, geeksforgeeks.org/pointer-array-array-pointer overiq.com/c-programming-101/pointers-and-2-d-arrays

Karm Patel 18.12.2020 17:25

@user3121023 user3121023 Да, это работает. Не могли бы вы уточнить свой ответ, почему это работает и где я делаю неправильно в своем коде?

Karm Patel 18.12.2020 17:26

Беглый взгляд показывает, что источники копировали друг друга. Но в любом случае ни один из источников не дает примера, как передать 2D-массив в функцию, поэтому вам нужны источники получше.

JHBonarius 18.12.2020 17:29

@JHBonarius Спасибо за ваш ответ, можете ли вы упомянуть какой-нибудь полезный ресурс, из которого я могу его получить?

Karm Patel 18.12.2020 17:34
*( *(arr + i) + j) — это очень запутанный способ написания arr[i][j].
tadman 18.12.2020 17:38

И вы должны прочитать все ошибки и предупреждения, которые дает вам компилятор, в том числе "передача аргумента 1" pointer_string_array_indexing "из несовместимого типа указателя"

JHBonarius 18.12.2020 17:39

Давняя традиция C заключается в создании NULL терминированных массивов, а не в блокировке их определенного размера. Как я бы рекомендовал это как char **s = { "abc", "def", NULL }. Затем вы можете перебирать этот список, пока не получите указатель NULL. Это не чистый многомерный массив, но это своего рода то, с чем вы работаете с данными в его самом элементарном представлении. Вы по-прежнему можете получить к нему доступ как s[i][j], если хотите.

tadman 18.12.2020 17:40
Почему в Python есть оператор &quot;pass&quot;?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Travel Booking Angular Template один из лучших Travel & Tour booking template in the world. 30+ валидированных HTML5 страниц, которые помогут...
0
8
205
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

Ваш массив объявлен как char S[][4]. Все символы в S находятся в непрерывном блоке памяти. Когда вы обращаетесь к S[i][j], скомпилированный код определяет адрес символа, на который вы ссылаетесь, вычисляя смещение, представленное i и j, как char *indexed_character_address = S + i*4 + j. Теперь скомпилированный код использует indexed_character_address для загрузки или сохранения, в зависимости от того, как используется S[i][j].

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

char *T[] = { "tuv", "wxyz" };

То, что компилятор делает за кулисами для создания этого массива, очень похоже на это:

const char hidden_tuv[4] = { 't', 'u', 'v', '\0' };
const char hidden_wxyz[5] = { 'w', 'x', 'y', 'z', '\0' };
char *T[2] = { hidden_tuv, hidden_wxyz };

Строки "tuv" и "wxyz" сначала размещаются в каком-то произвольном месте, нет гарантии, что они будут первыми или что они будут где-то рядом друг с другом. Затем создается и инициализируется другой массив с этими двумя произвольными указателями.

Код, сгенерированный компилятором для доступа к T[i][j], работает совершенно иначе, чем для S. Сначала он вычисляет адрес i-го указателя строки в T, затем загружает из памяти один из начальных адресов строки, затем использует j для смещения от начала этого адреса. Так:

char **address_in_T = T + i;
char *string_start_address = *address_in_T;
// now string_start_address is either hidden_tuv or hidden_wxyz
char *indexed_character_address = string_start_address + j;

Этот подробный код эквивалентен этому небольшому выражению:

char *indexed_character_address = T[i] + j;
                          //    or &(T[i][j])
                          //    or *(*(T + i) + j)

Ваша переменная S представляет собой двумерный массив символов, инициализированный строковыми данными, с типом char[2][4]. Моя переменная T представляет собой одномерный массив указателей на символы типа (char *)[2].

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

char c1 = S[i][j];   // actually reads *(S + i*4 + j)
char c2 = T[i][j];    // actually reads *( *(T + i) + j)

Другие вопросы по теме