Программирование DSP C/C++: разница в использовании имени массива и имени указателя Mon, October 23 2017  

Поделиться

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

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите 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