Как я могу перейти в положение указателя непосредственно без использования оператора++?


Я работаю с указателем на структуру. Я хочу знать, возможно ли перемещение непосредственно в определенную позицию без использования оператора ++.

#include <stdio.h>
#include <stdlib.h>

#define ARRAY_SIZE 10

struct dummy{
    int id;
    char buffer[10];
};

typedef struct dummy dummy_struct;

int main()
{
    int i=0;
    dummy_struct *ds = malloc(sizeof(dummy_struct)*ARRAY_SIZE);
    dummy_struct *iterator = ds;

    for(i=0;i<ARRAY_SIZE;i++)
    {
        iterator->id = i;
        sprintf(iterator->buffer,"%d",i);
        iterator++;
    }

    iterator = ds;

    for(i=0;i<ARRAY_SIZE;i++)
    {
        printf("%d:%s:%pn",iterator->id,iterator->buffer,iterator);
        iterator++;
    }

    // I want to access directly to 5th position
    iterator = ds + (sizeof(dummy_struct)*5);
    printf("5th position %d:%s:%pn",iterator->id,iterator->buffer,iterator);

    return 0;
}

Это утверждение

iterator = ds + (sizeof(dummy_struct)*5);

Не работает. Я буду признателен за любое предложение.

3 9

3 ответа:

Ну, арифметика указателей чтит тип данных!!

iterator = ds + 5;

Сделает свою работу.

Чтобы уточнить, приведенное выше выражение создаст указатель, переместив его 5 раз, умноженный на размер типа для ds, в байтах. Это то же самое, что &(ds[5]).

Для полноты объяснения, почему iterator = ds + (sizeof(dummy_struct)*5); неверно, здесь, по сути, вы пытаетесь переместить указатель на элемент с индексом как (sizeof(dummy_struct)*5, который находится далеко за пределами границ. Примечание пожалуйста, это вызывает неопределенное поведение !! Примечание ниже

Цитирование C11, Глава §6.5.6/P8

Когда выражение, имеющее целочисленный тип, добавляется к указателю или вычитается из него, то результат имеет тип операнда указателя. Если операнд указателя указывает на элемент объект массива, и массив достаточно велик, результат указывает на смещение элемента от исходный элемент такой, что разность индексов результирующего и исходного элементы массива равны целочисленному выражению. Другими словами, если выражение P указывает на i - й элемент объекта массива, выражения (P)+N (эквивалентно, N+(P)) и (P)-N (где N имеет значение n) указывают соответственно на i+n - й и i−n-й элементы объект array, при условии, что они существуют. [....]

И затем, относительно неопределенного поведения, упомянутого выше,

[....] Если оба указателя операнд и тот результат указывает на элементы одного и того же объекта массива или на один из последних объектов массива. элемент массива объекта, оценка не должна производить переполнение; в противном случае, поведение не определено. Если результат указывает на один из последних элементов объекта массива, то не должен использоваться в качестве операнда унарного оператора *, который вычисляется.


При этом утверждение printf() также ошибочно. У вас есть два спецификатора преобразования, но вы предоставили три аргумента. Это невредный , но бесполезный/бессмысленный.

Связанные, из главы §7.21.6.1 / P2,

[...] Если формат исчерпан, а аргументы остаются, то избыточные аргументы являются оцениваются (как всегда), но в остальном игнорируются. [...]

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

printf("5th position %d:%s:\n",ds[5].id,ds[5].buffer);

Поведение

iterator = ds + (sizeof(dummy_struct) * 5);

Является неопределенным, Если вы устанавливаете указатель за один после конечного элемента массива. Вы на самом деле устанавливаете iterator на большее количество элементов в массиве, чем вы думаете, с коэффициентом sizeof(dummy_struct)! Не делай этого.

Язык позволяет использовать нотацию iterator = ds + 5;. Эта идиоматическая арифметика указателя добавляет 5 множество sizeof(dummy_struct) к адресу iterator. Другими словами, компилятор выполняет настройку sizeof за вас. Это одна из причин, почему указательная арифметика настолько мощна.

Наконец, обратите внимание, что *(ds + 5) эквивалентно ds[5]. Я нахожу, что последнее дает больше ясности при работе с массивами.

Похоже, что вы пытаетесь сделать указатель iterator, указывающий на 5th элемент массива ds. Но это утверждение даст вам неверный результат:

iterator = ds + (sizeof(dummy_struct)*5);
Результатом

Будет суммарный размер всех элементов структуры dummy_struct, умноженный на 5, который будет добавлен к адресу, на который ссылается ds и присвоен iterator. Таким образом, iterator может указывать на место в памяти, которое не принадлежит вашей программе. Вам нужно сделать:

iterator = ds + 5;

Или вы также можете сделайте:

iterator = &ds[5];