Я очень смущен тем, что обозначают эти два обозначения.
Я знаю, что приоритет ()
больше, чем []
, значит ли это, что char(*name)[10]
— указатель, а char *name[10]
— массив?
Да, имя с char (*name)[10]
является указателем на массив из 10 символов (name = malloc(1000 * sizeof *name); strcpy(name[123], "foobar");
); с именем char *name[10]
представляет собой массив из 10 указателей на char (name[4] = malloc(42);
).
о, я думал, что char *name[10] является указателем на первый элемент массива «имя», то есть имя [0].
sizeof(char (*)[10] )
будет в 10 раз меньше, чем sizeof(char *[10])
@NeerajKumar «думал, что char *name[10] является указателем» -> Массивы не являются указателями. Указатели не являются массивами. Это как вы впервые запросили: «char *name[10] - это массив».
@chux-ReinstateMonica, пожалуйста, проясните мне одну вещь, сэр, когда я набираю char *a = "Hello"
, а затем использую printf("%s", a)
, тогда выводится вся строка «Привет». Значит ли это, что char *
эквивалентно string
как в C++. Если это не так, то, пожалуйста, помогите мне, как он печатает всю строку «Hello».
@NeerajKumar В C++ класс std::string отличается от массива символов. Вы не можете использовать, например, std::string s("Hello"); printf("%s\n", с);; Строковые литералы — это массивы символов.
NeerajKumar, «означает ли это, что char * эквивалентен строке, как в C++» --> не эквивалентен, хотя и имеет некоторое сходство. a
это указатель - адрес - это не строка. Это указатель на начало строки. printf("%s", a)
получает этот указатель и использует его для чтения и печати содержимого строки: первый символ, затем следующий до '\0'
. Очень похоже на адрес дома не в доме, а просто «указатель» на дом. Он не сообщает, где «заканчивается» дом, а только то, где он находится.
@chux-ReinstateMonica Я вас понял!, это означает, что char *a
является отправной точкой массива неизвестного размера, и когда мы используем printf("%s",a)
, он будет искать, пока '\0'
не будет найден, и напечатает строку. Итак, почему мы инициализируем массив символов, я имею в виду, что мы можем использовать char *arr
вместо char arr[10]
, поскольку выгодно, чтобы размер не был определен, и мы могли хранить столько, сколько захотим.
@NeerajKumar char *arr
— это адрес «дома» — какого-то дома — где-то, еще не определенного. char arr[10]
это дом - его содержимое еще не определено. Да, char *arr
может указывать на строку любого размера, но эта строка еще не определена. Мы инициализируем массив символов, чтобы создать строку.
@chux-ReinstateMonica хорошо, это означает, что использование char *arr
для строки не рекомендуется, мы должны использовать char arr[10]
. Спасибо за вашу помощь и потраченное драгоценное время на решение моей проблемы :-)
@NeerajKumar С char *arr
, arr
это не строка. Хотя это может указывать на одно. Передача указателей - хорошая практика. Однако объект должен где-то существовать.
@chux-ReinstateMonica хорошо, последнее сомнение, пожалуйста, в char *arr = "Hello"
, arr
быть указателем не принимает адрес, а принимает строку. Как это возможно, когда я использую char *arr = 'Z'
, он показывает ошибку, и я должен использовать char a = 'Z'
, а затем char *arr = &a
. Означает ли это, что в char *arr = "Hello"
двойные кавычки делают две вещи: создают строку с завершающим нулем и, во-вторых, предоставляют адрес первого символа для arr
?
@NeerajKumar char *arr = "Hello"
--> Да. Обратите внимание, что не следует пытаться писать в строковый литерал "Hello"
. ТТФН.
Давайте продолжим обсуждение в чате.
int *a[10]
— объявляет массив из 10 указателей на целое число.
int (*a)[10]
— объявляет указатель на массив из 10 целых чисел.
о, я думал, что char *name[10] является указателем на первый элемент массива «имя», то есть имя [0].
Эта декларация
char *name[10];
объявляет массив из 10 элементов типа char *
.
Например, такой массив можно инициализировать следующим образом
char *name[10] = { "Peter", "Tom", "Michael" };
Все элементы массива, не имеющие соответствующего инициализатора, будут неявно инициализированы с помощью NULL
. То есть приведенное выше объявление эквивалентно
char *name[10] =
{
"Peter", "Tom", "Michael", NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
Указатель на первый элемент массива будет выглядеть так
char **p = name;
Указатель на весь массив будет выглядеть так
char * ( *p )[10] = &name;
Эта декларация
char (*name)[10];
объявляет указатель на объект типа массива char[10]
.
Например, если у вас есть массив, объявленный как
char name_list[][10] =
{
"Peter", "Tom", "Michael"
};
то вы можете объявить указатель на первый элемент массива, например
char (*name)[10] = name_list;
Указатель на весь массив может быть объявлен как
char ( *p )[3][10] = &name_list;
Вот демонстрационная программа.
#include <stdio.h>
int main(void)
{
{
char *name[10] = { "Peter", "Tom", "Michael" };
char **p1 = name;
puts( *p1 );
char * ( *p2 )[10] = &name;
puts( ( *p2 )[0] );
// or
puts( **p2 );
}
putchar( '\n' );
{
char name_list[][10] =
{
"Peter", "Tom", "Michael"
};
char ( *p1 )[10] = name_list;
puts( *p1 );
char ( *p2 )[3][10] = &name_list;
puts( ( *p2 )[0] );
// or
puts( **p2 );
}
return 0;
}
Вывод программы
Peter
Peter
Peter
Peter
Peter
Peter
Имейте в виду, что строковые литералы — это const
. const char *name[10] = { "Peter", "Tom", "Michael" };
будет правильнее.
@ 12431234123412341234123 В C строковые литералы не являются const
, даже если код не должен пытаться их изменить.
@ 12431234123412341234123 В строковых литералах C есть типы непостоянных массивов символов, хотя вы не можете изменить строковый литерал.
*имя[10]
представляет собой массив из 10 указателей. Обычно они используются при работе с двумерными массивами.
(*имя)[10]
С другой стороны, это в основном указатель на массив из 10 целых чисел или что-то еще.