Имя массива это адрес первого элемента или указатель на его первый элемент в Си?
Есть код:
int arrOne[5] = {1,2,3,4,5};
Тут arrOne это адрес его первого элемент ? Или указатель на его первый элемент ? Или в указатель он превращается только когда это нужно (к примеру в арифметике адресов)? Или оба варианта верны ?
Немного другая тема:
int arrTwo[3][2] = {{1,2}, {3,4}, {5,6}};
А с двумерным массивом как ? Тут arrTwo это адрес первого элемента или указатель на его первый элемент т.е {1,2}? И получается arrTwo это адрес самого первого элемента {1,2} или же адрес первого элемента первого подмассива т.е {1}?
Ответы (2 шт):
переменная arrOne имеет тип массива int[5]. Может неявно преобразовываться в указатель на первый элемент типа int * в подходящем контексте.
во втором примере первый элемент массива имеет тип int[2], а указатель на него тип : int ( * ) [ 2 ]
int main()
{
int arrOne[5] = {1,2,3,4,5};
int * arrOnep = arrOne ;
int * arrOnep2 = & arrOne [ 0 ] ;
int arrTwo[3][2] = {{1,2}, {3,4}, {5,6}};
int ( * arrTwop ) [ 2 ] = arrTwo ;
int ( * arrTwop2 ) [ 2 ] = & arrTwo [ 0 ] ;
return 0;
}
Тут arrOne это адрес его первого элемент ? Или указатель на его первый элемент ? Или в указатель он превращается только когда это нужно (к примеру в арифметике адресов)? Или оба варианта верны ?
Немного запутанный вопрос, верный вариант: arrOne - это массив int длины 5 (т.е. третий или четвёртый). В частности, sizeof(arrOne) == 5*sizeof(int). Так же, для C++ при подстановках шаблонов, а для C в _Generic(), он отличается от указателей на элементы.
До C++17 была популярная идиома _countof(), её расширенная версия включена в стандарт как std::ssize() (std::size() - беззнаковый вариант, для циклов по unsigned):
template<class T, std::ptrdiff_t n>
constexpr static std::ptrdiff_t
_countof(T (&)[n]){ return n; }
Есть её безопасные варианты и для C11 (https://stackoverflow.com/a/57537491/8585880), но они немного длиннее.
А с двумерным массивом как ?
Примерно так же, в том смысле, что arrTwo массив длины 3 массивов int длины 2.
#include <print>
#include <vector>
#include "type_name.hpp" // https://stackoverflow.com/a/64490578/8585880
#define print_arr(a) \
(std::println("std::size({}) = {}, sizeof({}) = {}", \
(#a), std::size(a), (#a), sizeof(a)))
#define print_elem(a, e) \
(std::println("{:14} type: {}, offset: {}", \
(#e), \
type_name<decltype(e)>(), \
(char*)((void*)e) - (char*)((void*)a)))
using AInt = volatile int;
int main() {
int arrOne[5] = {1,2,3,4,5};
int arrTwo[3][2] = {{1,2}, {3,4}, {5,6}};
AInt aArrOne[5] = {1,2,3,4,5};
AInt aArrTwo[3][2] = {{1,2}, {3,4}, {5,6}};
print_arr(arrOne);
// print_arr(&arrOne[0]); // Ошибка при компиляции std::size()
print_elem(arrOne, arrOne);
print_elem(arrOne, &arrOne[0]);
print_elem(arrOne, &arrOne[4]);
print_arr(arrTwo);
print_arr(arrTwo[1]);
// print_arr(&arrTwo[1][1]); // Ошибка при компиляции std::size()
print_elem(arrTwo, arrTwo);
print_elem(arrTwo, &arrTwo[0]);
print_elem(arrTwo, &arrTwo[0][0]);
print_elem(arrTwo, &arrTwo[2]);
print_elem(arrTwo, &arrTwo[2][1]);
print_elem(aArrOne, aArrOne);
print_elem(aArrOne, &aArrOne[0]);
print_elem(aArrOne, &aArrOne[4]);
print_elem(aArrTwo, aArrTwo);
print_elem(aArrTwo, &aArrTwo[0]);
print_elem(aArrTwo, &aArrTwo[0][0]);
print_elem(aArrTwo, &aArrTwo[2]);
print_elem(aArrTwo, &aArrTwo[2][1]);
}
Выдаст примерно следующее:
std::size(arrOne) = 5, sizeof(arrOne) = 20
arrOne type: int[5], offset: 0
&arrOne[0] type: int *, offset: 0
&arrOne[4] type: int *, offset: 16
std::size(arrTwo) = 3, sizeof(arrTwo) = 24
std::size(arrTwo[1]) = 2, sizeof(arrTwo[1]) = 8
arrTwo type: int[3][2], offset: 0
&arrTwo[0] type: int (*)[2], offset: 0
&arrTwo[0][0] type: int *, offset: 0
&arrTwo[2] type: int (*)[2], offset: 16
&arrTwo[2][1] type: int *, offset: 20
aArrOne type: volatile int[5], offset: 0
&aArrOne[0] type: volatile int *, offset: 0
&aArrOne[4] type: volatile int *, offset: 16
aArrTwo type: volatile int[3][2], offset: 0
&aArrTwo[0] type: volatile int (*)[2], offset: 0
&aArrTwo[0][0] type: volatile int *, offset: 0
&aArrTwo[2] type: volatile int (*)[2], offset: 16
&aArrTwo[2][1] type: volatile int *, offset: 20