Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Industrial programming >> Язык C

Легкая инициализация массивов указателей в C: советы и лучшие практики

Указатель — переменная, хранящая адрес другой переменной. Имя переменной-указателя должно начинаться с символа *. Как и в случае с обычной переменной, мы можем объявить «массив указателей», где каждый индекс массива хранит адрес переменной массива.

Как инициализировать массив указателей в C?

Переменная-указатель может быть инициализирована при объявлении путём присваивания ей адреса существующей переменной. Следующий фрагмент показывает, как инициализировать указатель —

int x = 10;
int *y = &x;

По умолчанию все переменные, включая переменные-указатели, принадлежат классу хранения «auto». Это означает, что переменная-указатель будет хранить непредсказуемый, мусорный, случайный адрес памяти, что может привести к неопределённому поведению и потенциальным рискам для программы, таким как ошибки сегментации. Поэтому её следует инициализировать NULL, если у нас нет конкретного значения для сохранения при объявлении.

int *ptr = NULL;

«Массив указателей» хранит адрес в каждом элементе. Тип массива должен совпадать с типом целевой переменной.

Инициализация массива указателей с ключевым словом static

Можно также использовать ключевое слово static для инициализации массива указателей, сохраняющего 0 в каждом индексе.

Пример

#include <stdio.h>
int main(){
    static int *ptr[5];
    for (int i = 0; i < 5; i++){
        printf("ptr[%d] = %d\n", i, ptr[i]);
    }
    return 0;
}

Вывод

Запустите код и проверьте его вывод —

ptr[0]= 0
ptr[1]= 0
ptr[2]= 0
ptr[3]= 0
ptr[4]= 0

Инициализация массива целочисленных указателей

Здесь мы объявляем массив целочисленных указателей и сохраняем адреса трёх целочисленных переменных.

Пример

#include <stdio.h>
int main(){
    int a = 10, b = 20, c = 30;
    int *ptr[3] = {&a, &b, &c};
    for (int i = 0; i < 3; i++){
        printf("ptr[%d]: address: %d value: %d\n", i, ptr[i], *ptr[i]);
    }
    return 0;
}

Вывод

Запустите код и проверьте его вывод —

ptr[0]: address: 6422040 value: 10
ptr[1]: address: 6422036 value: 20
ptr[2]: address: 6422032 value: 30

Инициализация массива указателей прямыми адресами

Мы можем хранить адрес каждого элемента обычного массива в соответствующем элементе массива указателей.

Пример

#include <stdio.h>
int main(){
    int arr[] = {10, 20, 30};
    int *ptr[3] = {&arr[0], &arr[1], &arr[2]};
    for (int i = 0; i < 3; i++){
        printf("ptr[%d]: address: %d value: %d\n", i, ptr[i], *ptr[i]);
    }
    return 0;
}

Вывод

Запустите код и проверьте его вывод —

ptr[0]: address: 6422032 value: 10
ptr[1]: address: 6422036 value: 20
ptr[2]: address: 6422040 value: 30

Обход массива через его базовый адрес

Когда мы получаем базовый адрес массива (в данном случае &arr[0]), мы можем получить адреса его последующих элементов, зная, что указатель увеличивается на размер типа данных.

Таким образом, имея только базовый адрес (имя массива то же самое, что адрес 0-го элемента), мы можем обойти массив.

Пример 1

Посмотрите на следующий пример —

#include <stdio.h>
int main(){
    int arr[] = {10, 20, 30};
    int *ptr = arr;
    for (int i = 0; i < 3; i++){
        printf("ptr[%d]: address: %d value: %d\n", i, ptr+i, *(ptr+i));
    }
    return 0;
}

Вывод

Запустите код и проверьте его вывод —

ptr[0]: address: 6422020 value: 10
ptr[1]: address: 6422024 value: 20
ptr[2]: address: 6422028 value: 30

Пример 2: Обход двумерного массива с использованием массива указателей

В этом примере у нас есть двумерный массив. Адрес 0-го элемента каждой строки хранится в массиве указателей. При обходе адрес, сохранённый в каждом элементе массива указателей, указывающий на 0-й элемент соответствующей строки, увеличивается для получения значений в каждой строке.

#include <stdio.h>
int main(){
    // 2d array
    int arr[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
    };
    int ROWS = 2, COLS = 4;
    int i, j;
    // pointer
    int (*ptr)[4] = arr;
    // print the element of the array via pointer ptr
    for (i = 0; i < ROWS; i++) {
        for (j = 0; j < COLS; j++) {
            printf("%d ", *(ptr[i]+j));
        }
        printf("\n");
    }
    return 0;
}

Вывод

При запуске этот код выдаст следующий вывод —

1 2 3 4
5 6 7 8

Пример 3

Нам на самом деле не нужен массив указателей здесь, так как мы можем использовать имя этого двумерного массива как его базовый указатель и увеличивать его по строкам и столбцам для получения элементов в данном двумерном массиве —

#include <stdio.h>
int main(){
    // 2d array
    int arr[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
    };
    int ROWS = 2, COLS = 4;
    int i, j;
    // pointer
    int *ptr = arr;
    // print the element of the array via pointer ptr
    for (i = 0; i < ROWS; i++){
        for (j = 0; j < COLS; j++){
            printf("%d ", *(ptr + i * COLS + j));
        }
        printf("\n");
    }
    return 0;
}

Вывод

Вывод похож на предыдущий код —

1 2 3 4
5 6 7 8

Инициализация массива символьных указателей (строк)

В программировании на C строка — это массив типа данных char. Поскольку имя массива также представляет адрес его 0-го элемента, строку можно объявить как —

char arr[] = "Hello";

Используя указательную нотацию, строка присваивается указателю char как —

char *arr = "Hello";

Затем мы можем объявить массив указателей char для хранения нескольких строк следующим образом —

char *arr[3] = {"string1", "string2", "string3", ... };

Пример

В следующем примере массив указателей char используется для хранения названий языков программирования —

#include <stdio.h>
int main(){
    char *langs[10] = {
        "PYTHON", "JAVASCRIPT", "PHP", "NODE JS", "HTML",
        "KOTLIN", "C++", "REACT JS", "RUST", "VBSCRIPT"
    };
    for(int i = 0; i < 10; i++)
        printf("%s\n", langs[i]);
    return 0;
}

Вывод

При запуске этот код выдаст следующий вывод —

PYTHON
JAVASCRIPT
PHP
NODE JS
HTML
KOTLIN
C++
REACT JS
RUST
VBSCRIPT

В этой программе langs — указатель на массив из 10 строк. Следовательно, если langs[0] указывает на адрес 5000, то langs + 1 будет указывать на адрес 5004, хранящий указатель на вторую строку.

Поэтому мы также можем использовать следующую вариацию цикла для печати массива строк —

for (int i = 0; i < 10; i++){
    printf("%s\n", *(langs + i));
}

Инициализация динамического массива указателей

Можно использовать функцию malloc() для объявления и инициализации массива указателей динамическим способом.

Пример

Посмотрите на следующий пример —

#include <stdio.h>
int main(){
    int *arr = (int *)malloc(sizeof(int) * 5);
    for(int i = 0; i < 5; i++){
        arr[i] = i;
    }
    for (int x = 0; x < 5; x++){
        printf("%d %d\n", x, arr[x]);
    }
    return 0;
}

Вывод

При запуске этот код выдаст следующий вывод —

0 0
1 1
2 2
3 3
4 4

Вы можете даже запрашивать пользовательский ввод и присваивать значения элементам в массиве указателей —

for(i = 0; i < 5; i++){
    scanf("%d", &x);
    arr[i] = x;
}

Язык C

  1. Структуры против объединений в C: практическое руководство
  2. Типы данных в C: int, float, char и другие — полное руководство
  3. Управление потоком в C: операторы break и continue
  4. Понимание конструкторов в C++: конструкторы по умолчанию, параметризованные и копирования
  5. Классы хранения в C: область видимости, время жизни и производительность
  6. Многопоточность в C#: Повышение производительности и эффективности
  7. Освоение оператора break в C++
  8. Потоки в C++: cout, cin, cerr, clog — практическое руководство
  9. C#: обзор современного объектно-ориентированного языка от Microsoft
  10. Интерфейсы в C#: определение, пример и практическое применение