массив символов в структурном типе данных

#arrays #c #types #character

#массивы #c #типы #символ

Вопрос:

На самом деле у меня есть вопрос относительно концепции массива символов, особенно того, который объявлен и инициализирован, как показано ниже.

 char aString[10] = "";
 

Меня учили, что этот массив может хранить до 10 символов (индекс 0-9) и что в индексе 10 автоматически помещается завершающий символ null (я знаю, что доступ к нему был бы неправильным), так что, если мы используем функции обработки строк (printf, scanf, strcmp и т. Д.)они будут знать, когда строка заканчивается.

Однако, когда я попытался создать структурный тип данных, как показано ниже,

 typedef struct customer{
    char accountNum[10];
    char name[100];
    char idNum[15];
    char address[200];
    char dateOfBirth[10];
    unsigned long long int balance;
    char dateOpening[10];
}CUSTOMER;
 

вставил 10 символов в AccountNum (любым методом, например, scanf) и распечатал его, распечатанным будет AccountNum и значения в первом слове name (я знаю, что printf остановится на пробел или »). Это указывает на то, что массив символов не имеет завершающего значения null в конце массива.

Означает ли это, что если у нас есть массив символов размером 10 (char aString[10] ), его максимальное количество символов, которое он может хранить, равно 9 символам? или в структуре все работает по-другому? Было бы неплохо, если бы кто-нибудь мог помочь мне с концепцией, потому что кажется, что я, возможно, все это время работал с неопределенным поведением.

Комментарии:

1. Чему меня научили, так это тому, что этот массив может хранить до 10 символов (индекс 0-9) и что в индексе 10 автоматически помещается завершающий символ null , либо вас неправильно научили, либо вы ослышались. Всего 10 символов, включая завершающий символ null.

Ответ №1:

char aString[10] = «»;

Меня учили, что этот массив может хранить до 10 символов (индекс 0-9)

ДА.

и что в индексе 10 автоматически помещается завершающий символ null

Это неправильно. Во-первых, индекс 10 будет находиться за пределами массива. Компилятор, безусловно, не будет инициализировать данные за пределами памяти, которую он зарезервировал для массива.

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

В вашем примере строковый литерал имеет длину 1 char (нулевой ограничитель), поэтому весь массив в конечном итоге инициализируется нулями.

я знаю, что доступ к нему был бы неправильным

Нет проблем с доступом к нулевому терминатору, если он находится внутри границ массива.

такой, что если мы используем функции обработки строк (printf, scanf, strcmp и т.д.), Они будут знать, когда строка заканчивается.

Да, они ожидают строки в стиле C и поэтому будут искать нулевой ограничитель — если только им явно не указана фактическая длина строки, т. Е. С помощью модификатора точности для %s или с использованием strncmp() и т. Д.

Однако, когда я попытался создать структурный тип данных, как показано ниже,

<снип>

вставил 10 символов в AccountNum (любым методом, например, scanf) и распечатал его, распечатанным будет AccountNum и значения в первом слове name

Это означает, что вы либо забыли завершить нулевым завершением accountNum , либо, вероятно, переполнили его, написав в него слишком много символов. Например, это очень легко сделать при неправильном scanf() использовании , strcpy() , и т.д.

я знаю, что printf будет останавливаться на пробел или »

printf() не останавливается на пробеле, только на нулевом терминаторе. Если вы не укажете ему максимальную длину явно, например:

 CUSTOMER c;
strncpy(c.accountNum, "1234567890", 10); // <-- will not be null terminated!
printf("%.10s", c.accountNum); // <-- stops after printing 10 chars!
 

Если к моменту достижения 10-го символа он не столкнулся с нулевым терминатором, он остановится сам.

Это указывает на то, что массив символов не имеет завершающего значения null в конце массива.

Массив — это просто массив, в нем нет ограничителя, только размер. Если вы хотите обрабатывать массив символов как строку в стиле C, то вы несете ответственность за то, чтобы убедиться, что массив содержит nul в нем символ. Но это всего лишь семантика символьных данных, компилятор ничего не сделает для обеспечения такого поведения для вас (за исключением одного случая инициализации символьного массива строковым литералом).

Означает ли это, что если у нас есть массив символов размером 10 (char aString[10] ), его максимальное количество символов, которое он может хранить, равно 9 символам?

Его максимальное хранилище всегда будет составлять 10 символов, точка. Но если вы хотите обрабатывать массив как строку в стиле C, то один из этих символов должен быть a nul .

или в структуре все работает по-другому?

Нет. Где используется массив, не имеет значения. Компилятор обрабатывает весь массив одинаково, независимо от контекста (за исключением одного особого случая инициализации символьного массива строковым литералом).

Ответ №2:

Меня учили, что этот массив может хранить до 10 символов (индекс 0-9) и что в индексе 10 автоматически помещается завершающий символ null (я знаю, что доступ к нему был бы неправильным), так что, если мы используем функции обработки строк (printf, scanf, strcmp и т. Д.)они будут знать, когда строка заканчивается.

Да, но доступ к нулевому завершающему символу абсолютно безопасен.

вставил 10 символов в AccountNum (любым методом, например, scanf) и распечатал его, распечатанным будет AccountNum и значения в первом слове name (я знаю, что printf остановится на пробел или »). Это указывает на то, что массив символов не имеет завершающего значения null в конце массива.

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

Означает ли это, что если у нас есть массив символов размером 10 (char aString[10] ), его максимальное количество символов, которое он может хранить, равно 9 символам?

ДА.

или в структуре все работает по-другому?

Здесь нет никакой разницы.

Комментарии:

1. Правильный способ справиться с проблемой printf() прохождения мимо конца customer::accountNum[] — это либо завершить с нулевым завершением accountNum[] , либо просто указать printf() размер accountNum[] , чтобы он знал, когда остановиться, если нулевой ограничитель отсутствует.