Программирование DSP C/C++: разница в использовании имени массива и имени указателя Sat, May 25 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.

C/C++: разница в использовании имени массива и имени указателя Печать
Добавил(а) microsin   

Если Вы не первый год программируете на языке C, то наверное давно заметили, что имена массивов и имена указателей можно использовать примерно одинаково. Например, у нас есть массив char Array[10] и указатель char *ptr, и для обоих имен Array и ptr допустимы одинаковые операции:

char Array[10];
char *ptr1;
char *ptr2;
 
ptr = Array;
//Обнуление блока памяти через имя массива
// и имя указателя работает одинаково:
memset(Array,0,sizeof(Array));
memset(ptr,0,10);
Array[0] = 'A';   // и так можно...
ptr1[1]  = 'B';   // и так тоже можно, теперь в массиве
                  // Array содержится строка "AB"...
//Указателю можно присвоить как адрес массива,
// так и значение указателя:
ptr2 = Array+1;
ptr2 = ptr+2;

Возникает логичный вопрос: может быть, и массив, и указатель это одно и то же? Но почему тогда нельзя объявить массив, а потом в заголовочном файле объявить это же имя через extern как указатель? 

char Array[10];
...
extern char *Array;  //так нельзя, компилятор выдаст ошибку,
extern char Array[]; //а так можно, проблем нет.

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

Указатель Массив
1. Указатель это некоторое место в памяти, которое содержит адрес какой-то другой области памяти. 1. Массив это одиночный, заранее выделенный кусок памяти, где однотипные элементы непрерывно следуют друг за другом. Массив имеет изначально фиксированный размер и фиксированное размещение.
2. Несмотря на то, что указатель можно инициализировать при определении, нельзя при определении указателя проинициализировать память, на которую указывает указатель. 2. Содержимое массива, на которое указывает его имя, может быть проинициализировано в момент определения массива. Например int num[] = {2, 4, 5};
3. По своей природе указатель динамичен. Часто он используется для указания на выделенный блок памяти, у которой может быть впоследствии изменен размер или которая может быть позже освобождена. Также указатели используются для массивов, имя которых передается в функцию в качестве параметра (см. пример вызова memset с массивом Array). 3. Массив по своей природе статичен. Т. е. память, которая выделена под массив, не может изменить свой размер, и не может быть впоследствии освобождена.
4. Двоичный код, который генерируется для работы с указателями, отличается от кода, который генерируется при работе с массивами. 4. Двоичный код, который генерируется для работы с указателями, отличается от кода, который генерируется при работе с массивами.

[Явные отличия указателя и массива]

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

#include < stdio.h >
 
int main()
{
   int arr[] = {10, 20, 30, 40, 50, 60};
   int *ptr = arr;
    
   // будет выведено sizof(int) * (количество элементов в массиве arr[])
   printf("Размер arr[] равен %d\n", sizeof(arr));
 
   // выведенный размер указателя будет одинаковым для всех типов
   // указателей (char *, void *, и т. д.)
   printf("Размер ptr равен %d", sizeof(ptr));
   return 0;
}

Этот пример выведет следующее:

Размер arr[] равен 24
Размер ptr равен 4

Также нельзя назначить любой адрес переменной массива:

#include < stdio.h >
 
int main()
{
   int arr[] = {10, 20}, x = 10;
   int *ptr = &x;    // эта строка скомпилируется нормально
   arr = &x;         // в этом месте компилятор выдаст ошибку
   return 0;
}

Компилятор выведет примерно следующее:

Compiler Error: incompatible types when assigning to
              type 'int[2]' from type 'int *'

Таким образом, можно сделать вывод, что массив определяется как постоянный указатель, у которого не может быть изменен адрес (char const *Array).

[Чем похожи указатель и массив]

Хотя массив и указатель - разные сущности языка C, некоторые их свойства выглядят одинаково.

1. Имя массива дает адрес первого элемента массива. Этот адрес можно присваивать указателю. Пример:

#include < stdio.h >
 
int main()
{
   int arr[] = {10, 20, 30, 40, 50, 60};
   int *ptr = arr;   // Значению указателя будет присвоен адрес массива
   printf("Значение первого элемента равно %d", *ptr);
   return 0;
}

Если пример запустить, то он выведет следующее:

Значение первого элемента равно 10

2. К элементам массива можно получить доступ с помощью арифметики указателей. Компилятор использует эту арифметику для доступа к элементу массива. Например, выражение наподобие "arr[i]" обрабатывается компилятором как *(arr + i). Так что выражения наподобие *(arr + i) работают для массива так же, как и выражения наподобие ptr[i] для указателя.

#include < stdio.h >
 
int main()
{
   int arr[] = {10, 20, 30, 40, 50, 60};
   int *ptr = arr;
   printf("arr[2] = %d\n", arr[2]);
   printf("*(ptr + 2) = %d\n", *(arr + 2));
   printf("ptr[2] = %d\n", ptr[2]);
   printf("*(ptr + 2) = %d\n", *(ptr + 2));
   return 0;
}

Этот код выведет:

arr[2] = 30
*(ptr + 2) = 30
ptr[2] = 30
*(ptr + 2) = 30

3. Если массив передается в параметре функции, то он всегда передается как указатель, даже если указать имя массива с квадратными скобками. Пример:

#include < stdio.h >
 int fun(int ptr[])
{
   int x = 10;
 
   // Будет выведен размер указателя
   printf("sizeof(ptr) = %d\n", sizeof(ptr));
 
   // Это возможно, потому что ptr это указатель, а не массив.
   ptr = &x;
 
   printf("*ptr = %d ", *ptr);
 
   return 0;
}int main()
{
   int arr[] = {10, 20, 30, 40, 50, 60};
   fun(arr);
   return 0;
}

Код выведет:

sizeof(ptr) = 4
*ptr = 10

[Ссылки]

1. Difference between pointer and array in C? site:geeksforgeeks.org.

 

Добавить комментарий


Защитный код
Обновить

Top of Page