Доступ к массиву int, переданному как недействительный указатель segfaults

Я играю с указателями и наткнулся на эту проблему. Как и в этом вопрос, мне нужна общая сигнатура метода для функции foo, поэтому я выбрал void * input в качестве параметра. По причинам тестирования я применил указатель void к указателю int **, чтобы использовать его как 2D-массив.

#include <stdio.h>
#include <stdlib.h>
void * foo(void *input, size_t mySize)
{
    for (size_t i = 0; i < mySize; ++i)
    {
        for (size_t j = 0; j < mySize; ++j)
        {
            ((int **)input)[i*mySize][j] = 10*i+j;
        }
    }
    return input;
}

int main(int argc, char const *argv[])
{
    size_t const mySize = 10;
    void * myMemory, * testPtr;

    myMemory = malloc(mySize * mySize * sizeof(int));

    testPtr = foo(myMemory, mySize);
    free(testPtr);
    return 0;
}

Теперь я подумал, что использование оператора [] будет таким же, как добавление int к указателю, например. что ((int **)input[i][j] будет таким же, как `((int **) input) + i + j

Но доступ к входному массиву в foo segfaults и использование gdb показывает мне

(gdb) p ((int **)input)[i][j]
Cannot access memory at address 0x0
(gdb) p ((int **)input)+i+j
$25 = (int **) 0x405260

так что очевидно есть разница. И поэтому я запутался.

((int **)input)[i*mySize][j] Боюсь, это вряд ли сработает. Почему не просто ((int*)input)[i * mySize + j] = 10 * i + j;?
Scheff's Cat 15.12.2018 10:10

Вам нужно рассматривать его как массив 2d, а не использовать его как массив 2d.

kiran Biradar 15.12.2018 10:10

Учтите, что int a[A][B] означает массив int[B]. Но если вы приведете указатель void* к другому указателю int**, откуда (TH) компилятор должен знать, какое измерение массива вы имеете в виду ...

Scheff's Cat 15.12.2018 10:14
((int **)input[i][j] - это двухуровневый указатель доступа, эквивалентный *(*((int**)input + i) + j) (обратите внимание, что каждый [] включает в себя уважение). Вы, вероятно, захотите (int*)[i + j].
yeputons 15.12.2018 10:15

Относительно общей функции (интерфейса): может быть, вы могли бы взглянуть на qsort(). Это C-ish версия универсальной функции сортировки. Я имею в виду, в частности, как они описывают массив и элементы, переданные для создания функции «в общем». Конечно, в стандартной библиотеке C есть и другие примеры - qsort() был только первым, что пришло мне в голову.

Scheff's Cat 15.12.2018 10:17

Пожалуйста, прочтите stackoverflow.com/questions/4470950/… и stackoverflow.com/questions/7586702/…

Ilja Everilä 15.12.2018 12:07
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
108
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы выделили одномерный массив с элементами mySize * mySize. int ** - это массив указателей на int, вам нужно

int **array2d;
int *p;
array2D = malloc(ROWS * sizeof(int*) + ROWS * COLUMNS * sizeof(int));
p = (int*) &array2d[ROWS];
for (size_t i = 0; i < ROWS; ++i)
    array2d[i] = &p[i * COLUMNS];

теперь может работать array2d [row] [column].

Или, как уже было предложено, используйте одномерный массив и формулы массива [строка * COLUMNS + столбец].

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

Хотя массивы и указатели похожи, они не совпадают.

Массив - одномерный или многомерный - представляет собой непрерывный фрагмент памяти, содержащий определенный тип данных. Например, int arr [10] объявляет arr как 10 непрерывных int в памяти. int multi_arr[5][10] объявляет multi_arr как 5 массивов из 10 непрерывных int в памяти.

Кроме того, имя arr будет базовым адресом этого массива, и его передача функции будет такой же, как передача &arr[0].

Но на этом сходство заканчивается. Многомерный массив (технически) не может быть преобразован в указатель на указатель, а затем обратно.

Если вышеупомянутый arr указывает на блок int, то разыменование первого измерения int ** ptr приведет вас к блоку указателей на int. Разыменование тот не приведет вас глубже в этот блок, как это сделал бы многомерный массив, скорее, он мог бы указывать куда угодно.

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