#c #arrays #string #pointers
#c #массивы #строка #указатели
Вопрос:
Здравствуйте, я новичок на этом сайте, и мне нужна некоторая помощь в понимании того, что будет считаться «нормой» при кодировании структур на C, для которых требуется строка. По сути, мне интересно, какой из следующих способов будет считаться «отраслевым стандартом» при использовании структур на C для отслеживания ВСЕЙ памяти, необходимой структуре:
1) Строка фиксированного размера:
typedef struct
{
int damage;
char name[40];
} Item;
Теперь я могу получить размер, используя sizeof(Item)
2) Указатель на символьный массив
typedef struct
{
int damage;
char *name;
} Item;
Я знаю, что могу сохранить размер name
, используя вторую переменную, но есть ли другой способ?
i) есть ли какие-либо другие преимущества использования фиксированного размера (1)
char name[40];
по сравнению с выполнением следующего и использованием указателя на массив символов (2)?
char *name;
и если да, то в чем преимущество?
ii) Кроме того, строка, использующая указатель на массив символов (2), будет сохранена последовательно и сразу после структуры (сразу после указателя на строку) или она будет сохранена где-то еще в памяти?
iii) Я хотел бы знать, как можно найти длину char *
строковой переменной (без использования size_t
, или целочисленное значение для хранения длины)
Комментарии:
1. Почему это помечено C ?
2. @Rapptz: Я полагаю, потому, что код C часто использует и предоставляет C-совместимые API, поскольку они гораздо более совместимы с другими языками
3. Для C идиоматично использовать
std::string
—struct Foo { std::string f; };
.4. @CaptainObvlious: нет, если вам нужно записать эту структуру на диск или вернуть ее на другой язык.
5. Строки фиксированной длины заманчивы, если вы хотите сохранять и загружать свои структуры в двоичном виде на / с диска или по сети (и не нуждаются в переносимости), потому что это может избавить вас от многих проблем с сериализацией / десериализацией. В большинстве других случаев динамически выделяемые строки, вероятно, лучше, поскольку они, вероятно, сэкономят вам много памяти.
Ответ №1:
В основном существует 3 общих соглашения для строк. Все три находятся в свободном доступе, как для представления в памяти, так и для хранения / передачи.
- Фиксированный размер. Доступ очень эффективен, но если фактическая длина меняется, вы оба теряете место и нуждаетесь в одном из приведенных ниже методов для определения конца «реального» содержимого.
- Длина с префиксом. Дополнительное пространство включается в динамическое распределение для хранения длины. Из указателя вы можете найти как содержимое символа, так и длину, непосредственно предшествующую ему. Пример: BSTR Иногда длина кодируется для большей экономии места для коротких строк. Пример: ASN-1
- Завершается. Строка продолжается до первого появления символа завершения (обычно NUL), и содержимое не может содержать этот символ. Вариации сделали завершение двумя NUL последовательно, чтобы в строке могли существовать отдельные символы NUL, которые затем часто обрабатываются как упакованный список строк. Другие варианты используют кодировку, такую как заполнение байтами (UTF-8 также будет работать), чтобы гарантировать, что существует некоторый код, зарезервированный для завершения, который никогда не может появиться в закодированной версии содержимого.
В третьем случае есть функция, например, strlen
для поиска терминатора и определения длины.
Оба случая, в которых используются указатели, могут указывать на данные, следующие сразу за фиксированной частью структуры, если вы тщательно распределите их таким образом. Если вы хотите принудительно выполнить это, используйте гибкий массив в конце вашей структуры (указатель не требуется). Вот так:
typedef struct
{
int damage;
char name[]; // terminated
} Item;
или
typedef struct
{
int damage;
int length_of_name;
char name[];
} Item;
Комментарии:
1. Я думаю, что это называется «гибким», а не «рваным», и оно поддерживается не всеми компиляторами.
2. @anatolyg: Спасибо за это. Я думаю, что это стандартно для C и незаконно в C ?
3. @BenVoigt, AFAIK, да, незаконно в C .
4. @BenVoigt Я предполагаю, что это C99, и поэтому не поддерживается Microsoft (никогда не пробовал).
5. @anatolyg: Я думал, Microsoft поддерживает это как расширение?
Ответ №2:
1) есть ли какие-либо другие преимущества использования фиксированного размера (1)
char name[40];
по сравнению с выполнением следующего и использованием указателя на массив символов (2)?
char *name;
и если да, то в чем преимущество?
С вашим массивом, объявленным как char name[40];
пространство для имени, уже выделено, и вы можете свободно копировать информацию в name
from name[0]
through name[39]
. Однако в случае char *name;
, это просто указатель на символ и может использоваться для указания на существующую строку в памяти, но сам по себе не может использоваться для копирования информации, пока вы не выделите память для хранения этой информации. Итак, допустим, у вас есть строка из 30 символов, которую вы хотите скопировать name
, объявленная как char *name;
, вы должны сначала выделить malloc
30 символов плюс дополнительный символ для хранения символа, заканчивающегося нулем:
char *name;
name = malloc (sizeof (char) * (30 1));
Затем вы можете свободно копировать информацию в / из name
. Преимущество динамического выделения заключается в том, что вы можете realloc
использовать память name
, если информация, которую вы храните в name, увеличивается. более 30 символов. Дополнительное требование после выделения памяти для name
вы несете ответственность за освобождение выделенной вами памяти, когда она больше не нужна. Это грубый набросок плюсов / минусов / требований для использования одного в отличие от другого.
Ответ №3:
Если вы знаете максимальную длину нужной вам строки, вы можете использовать массив символов. Однако это означает, что вы будете использовать больше памяти, чем обычно используете с динамически распределяемыми символьными массивами. Кроме того, взгляните на CString, если вы используете C . Вы можете найти длину массива символов, используя strlen . В случае статического выделения я полагаю, что это будет частью переменной. Динамический может быть где угодно в куче.