символ * против символа[] и многое другое

#arrays #c #string #pointers

Вопрос:

Меня смущает то, как C обрабатывает строки и char * vs char[] .

 char name[10] = "asd";
printf("%pn%p", amp;name, amp;name[0]); //0x7ffed617acd
                                                                //0x7ffed617acd
 

Если этот код дает одинаковые адреса для обоих аргументов, означает ли это, что компилятор C принимает массивы символов (строки) в качестве указателя на первый символ в массиве и перемещается в памяти, пока не получит нулевой терминатор? Почему бы не произошло то же самое, если бы мы изменили char name[] на char *name ? (Я знаю, что они отличаются, но что заставляет C воспринимать и то, и другое по-разному?)

Я знаю, что массивы не могут быть назначены после объявления (если вы не использовали что-то вроде strcpy, strcat), что также сбивает с толку. Почему бы C не принять их за любой другой тип данных? (Что-то подсказывает мне, что у компилятора есть определенный addr для него, в то время как вы можете назначить char* любое местоположение в mem, так как это указатель).

Я знаю, что char * у них фиксированный размер, в отличие char[] от которого char * их нельзя использовать для первого аргумента strcat .

Ответ №1:

в языке Си «строка» представляет собой массив типа «символ» (заканчивается на ). Когда вы ссылаетесь на массив в C, вы используете указатель на первый элемент. В данном случае ( char * ).

В соответствии со стандартом ANSI-C имя массива является указателем на первый элемент.

Возможность писать name вместо amp;name[0] — это синтаксический сахар. Точно так же доступ к записи элемента массива name[i] аналогичен записи *(name i) .

Ответ №2:

означает ли это, что компилятор c принимает массивы символов (строки) в качестве указателя на первый символ в массиве

Массив-это не указатель. Но массив будет неявно преобразован в указатель на первый элемент. Такое преобразование называется «разложением».

… и перемещается в памяти, пока не получит нулевой терминатор???

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

Почему бы не сделать то же самое, если бы мы изменили имя символа[] на имя символа*?

Ваша посылка ошибочна. Вы можете выполнять итерацию массива напрямую, а также с помощью указателя.

Если этот код дает одинаковые адреса для обоих аргументов, означает ли это

Адрес объекта — это первый байт объекта. Этот «тот же адрес» означает, что первый байт первого элемента массива находится по тому же адресу, что и первый байт массива в целом.

Я знаю, что массивы не могут быть назначены после объявления (если вы не использовали что-то вроде strcpy, strcat), что также сбивает с толку.

strcpy Ни strcat и не назначайте массив. Они назначают элементы массива, что вы также можете сделать, не вызывая эти функции.

Почему бы C не принять их за любой другой тип данных?

Этот вопрос неясен. Что вы подразумеваете под «С их принятием»? Почему вы думаете, что C должен использовать другой тип данных? Какой тип данных, по вашему мнению, он должен принимать?


 char name[10] = "asd";
printf("%pn%p", amp;name, amp;name[0]);
 

Аргументы имеют тип char(*)[10] и char* соответственно. Спецификатор %p формата требует, чтобы аргумент имел тип, аналогичный void* тому, который не похож на эти аргументы. Передача аргумента типа, отличного от требуемого спецификатором формата, приводит к неопределенному поведению. При использовании следует использовать другие типы указателей void* %p .