C Арифметика указателей

Указатели в C

. Поскольку ptr — указатель типа char, при инкременте он перемещается на sizeof(char) байт, то есть на 1 байт.

Предположим,ptr— это целочисленный указатель, указывающий на адрес 1000, и это 32-битное целое число. Выполним следующую арифметическую операцию над этим указателем:

ptr++

После выполнения вышеуказанных операцийptrбудет указывать на ячейку 1004, потому что каждый раз, когда ptr инкрементируется, он будет указывать на следующую ячейку целого числа, то есть на 4 байта вперёд от текущей позиции. Эта операция перемещает указатель на следующую ячейку памяти, не затрагивая фактическое значение в этой ячейке памяти. ЕслиptrЕсли он указывает на символ по адресу 1000, вышеуказанная операция заставит указатель указывать на ячейку 1001, потому что следующая позиция символа находится по адресу 1001.

Подведём итог:

  • Каждый инкремент указателя фактически заставляет его указывать на ячейку памяти следующего элемента.
  • Каждый декремент указателя заставляет его указывать на ячейку памяти предыдущего элемента.
  • Количество байтов, на которое указатель смещается при инкременте или декременте, зависит от размера типа данных переменной, на которую он указывает; например, int занимает 4 байта.

Инкремент указателя

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

Операция инкремента указателя выполняет соответствующее смещение в памяти на основе типа данных, на который указывает указатель.

В программах мы предпочитаем использовать указатели вместо массивов, потому что переменный указатель можно инкрементировать, а массив инкрементировать нельзя; массив можно рассматривать как константный указатель. Следующая программа инкрементирует переменный указатель, чтобы последовательно обращаться к каждому элементу массива:

Пример

#include <stdio.h> const int MAX = 3; int main () { // Определяем целочисленный массив int var[] = {10, 100, 200}; // Определяем целочисленную переменную i и целочисленный указатель ptr int i, *ptr; // Направить указатель ptr на начальный адрес массива var ptr = var; // Пройти по массиву for ( i = 0; i < MAX; i++) { // Вывести адрес, на который указывает текущий указатель ptr printf("Адрес памяти: var[%d] = %p\n", i, ptr ); // вывести значение по адресу, на который указывает текущий указатель ptr printf("Сохранённое значение: var[%d] = %d\n", i, *ptr ); // Переместить указатель ptr на позицию следующего элемента массива ptr++; } return 0; }

Когда приведенный выше код скомпилирован и выполнен, он выдает следующие результаты:

存储地址:var[0] = e4a298cc
存储值:var[0] = 10
存储地址:var[1] = e4a298d0
存储值:var[1] = 100
存储地址:var[2] = e4a298d4
存储值:var[2] = 200

Инкремент указателя на символ:

Пример

#include <stdio.h>

int main() {
    char str[] = "Hello";
    char *ptr = str;  // Указатель указывает на первый символ строки

    printf("Начальный символ: %c\n", *ptr);  // Вывести H

    ptr++;  // Увеличить указатель, чтобы он указывал на следующий символ
    printf("Символ после инкремента: %c\n", *ptr);  // Вывод e

    return 0;
}

В этом примере ptr++ заставляет указатель переместиться из str

Когда приведенный выше код скомпилирован и выполнен, он выдает следующие результаты:

初始字符: H
递增后字符: e

Инкремент указателя на структуру:

Пример

#include <stdio.h>

struct Point {
    int x;
    int y;
};

int main() {
    struct Point points[] = {{1, 2}, {3, 4}, {5, 6}};
    struct Point *ptr = points;  // Указатель указывает на первый элемент массива структур

    printf("Начальная точка: (%d, %d)\n", ptr->x, ptr->y);  // Вывод (1, 2)

    ptr++;  // Инкрементируем указатель, чтобы он указывал на следующую структуру
    printf("Точка после инкремента: (%d, %d)\n", ptr->x, ptr->y);  // Вывод (3, 4)

    return 0;
}

. Поскольку ptr — указатель типа struct Point, при его инкременте он смещается на sizeof(struct Point) байт.

Когда приведенный выше код скомпилирован и выполнен, он выдает следующие результаты:

初始点: (1, 2)
递增后点: (3, 4)

Декрементирование указателя

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

Выполнение операции декремента для указателя означает вычитание размера в байтах его типа данных из значения, как показано ниже:

Пример

#include <stdio.h> int main() { int arr[] = {10, 20, 30, 40, 50}; int *ptr = &arr[4]; // Указатель указывает на последний элемент массива printf("Начальное значение: %d\n", *ptr); // Вывод 50 ptr--; // Декрементируйте указатель, чтобы он указывал на предыдущий целочисленный элемент printf("Значение после декремента: %d\n", *ptr); // Вывод 40 ptr--; // Снова декрементируйте указатель printf("Значение после повторного декремента: %d\n", *ptr); // Вывод 30 return 0; }

Когда приведенный выше код скомпилирован и выполнен, он выдает следующие результаты:

初始值: 50
递减后值: 40
再次递减后值: 30

Декремент указателя на символ:

Пример

#include <stdio.h>

int main() {
    char str[] = "Hello";
    char *ptr = &str[4];  // Указатель указывает на последний символ 'o' строки

    printf("Начальный символ: %c\n", *ptr);  // Вывод o

    ptr--;  // Уменьшить указатель, чтобы он указывал на предыдущий символ
    printf("Уменьшенный символ: %c\n", *ptr);  // Вывод l

    ptr--;  // Снова уменьшить указатель
    printf("Уменьшенный символ снова: %c\n", *ptr);  // Вывод l

    return 0;
}

Когда приведенный выше код скомпилирован и выполнен, он выдает следующие результаты:

初始字符: o
递减后字符: l
再次递减后字符: l

Уменьшение указателя на структуру:

Пример

#include <stdio.h>

struct Point {
    int x;
    int y;
};

int main() {
    struct Point points[] = {{1, 2}, {3, 4}, {5, 6}};
    struct Point *ptr = &points[2];  // Указатель указывает на последний элемент массива структур

    printf("Начальная точка: (%d, %d)\n", ptr->x, ptr->y);  // Вывод (5, 6)

    ptr--;  // Уменьшить указатель, чтобы он указывал на предыдущую структуру
    printf("Уменьшенная точка: (%d, %d)\n", ptr->x, ptr->y);  // Вывод (3, 4)

    ptr--;  // Снова уменьшить указатель
    printf("Уменьшенная точка снова: (%d, %d)\n", ptr->x, ptr->y);  // Вывод (1, 2)

    return 0;
}

Когда приведенный выше код скомпилирован и выполнен, он выдает следующие результаты:

初始点: (5, 6)
递减后点: (3, 4)
再次递减后点: (1, 2)

Сравнение указателей

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

Указатели можно сравнивать с помощью операторов отношения, таких как==、!=、<、>、<=и>=Если p1 и p2 указывают на две связанные переменные, например на разные элементы одного и того же массива, то p1 и p2 можно сравнивать по величине.

Ниже приведены примеры кода, показывающие, как сравнивать указатели и выводить результаты.

Сравнение указателей на равенство:

Пример

#include <stdio.h> int main() { int a = 5; int b = 10; int *ptr1 = &a; int *ptr2 = &a; int *ptr3 = &b; if (ptr1 == ptr2) { printf("ptr1 и ptr2 указывают на один и тот же адрес памяти\n"); // Эта строка будет выведена } else { printf("ptr1 и ptr2 указывают на разные адреса памяти\n"); } if (ptr1 != ptr3) { printf(""ptr1 и ptr3 указывают на разные адреса памяти\n"); // Эта строка будет выведена } else { printf("ptr1 и ptr3 указывают на один и тот же адрес памяти\n"); } return 0; }

Когда приведенный выше код скомпилирован и выполнен, он выдает следующие результаты:

ptr1 和 ptr2 指向相同的内存地址
ptr1 和 ptr3 指向不同的内存地址

Сравнение размера указателя:

Пример

#include <stdio.h>

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int *ptr1 = &arr[1];  // Указывает на arr[1], значение 20
    int *ptr2 = &arr[3];  // Указывает на arr[3], значение 40

    if (ptr1 < ptr2) {
        printf("ptr1 находится перед ptr2\n");  // Эта строка будет выведена
    } else {
        printf("ptr1 находится после ptr2 или на той же позиции\n");
    }

    if (ptr1 > ptr2) {
        printf("ptr1 находится после ptr2\n");
    } else {
        printf("ptr1 находится перед ptr2 или на той же позиции\n");  // Эта строка будет выведена
    }

    return 0;
}

Когда приведенный выше код скомпилирован и выполнен, он выдает следующие результаты:

ptr1 在 ptr2 之前
ptr1 在 ptr2 之前或相同位置

Перебор массива и сравнение указателей:

Пример

#include <stdio.h>

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int *start = arr;           // Указывает на первый элемент массива
    int *end = &arr[4];         // Указывает на последний элемент массива
    int *ptr;

    for (ptr = start; ptr <= end; ptr++) {
        printf("Значение, на которое указывает текущий указатель: %d\n", *ptr);
    }

    return 0;
}

Когда приведенный выше код скомпилирован и выполнен, он выдает следующие результаты:

当前指针指向的值: 10
当前指针指向的值: 20
当前指针指向的值: 30
当前指针指向的值: 40
当前指针指向的值: 50

Итог

  • Сравнение на равенство (==и!=): Используется для определения, указывают ли два указателя на одну и ту же ячейку памяти.
  • Сравнение по величине (<, >, <=, >=): Обычно используется, когда указатели перемещаются по массивам или блокам памяти, чтобы определить, находится ли один указатель до или после другого указателя.
Обратите внимание, что сравнение указателей имеет смысл только тогда, когда указатели указывают на один и тот же массив или один и тот же блок памяти; в противном случае поведение не определено.

Указатели в C

Другие расширения