Ініціалізація масиву символів


119

Я не впевнений, що буде в масиві char після ініціалізації наступними способами.

1. char buf[10] = "";
2. char buf[10] = " ";
3.char buf[10] = "a";

Для випадку 2, я думаю , buf[0]повинно бути ' ', buf[1]має бути '\0', і від buf[2]до buf[9]буде випадковим зміст. Для випадку 3, я думаю , buf[0]повинно бути 'a', buf[1]має бути «\ 0», і від buf[2]до buf[9]буде випадковим зміст.

Це правильно?

А для випадку 1, що буде у buf? buf[0] == '\0'а від buf[1]до buf[9]буде випадковий вміст?


2
Ну, мій компілятор не приймає ваш (виправлений) код: "тип масиву 'char [10]' не призначається".
Мартін Р

@MartinR зараз це запрацює ...
lkkeepmoving

1
@lkkeepmoving: char buf[10]; buf = "a";зовсім НЕ компілювати. - Спробуйте спочатку, а потім скопіюйте / вставте власний код у запитання. Це економить багато роботи для вас і для всіх читачів вашого питання.
Martin R

@MartinR Вибачте за це. Я думав, що можу призначити buf [] останнього, але, здається, ні. Тепер код працює.
lkkeepmoving

Відповіді:


222

Це не спосіб ініціалізації масиву, а для:

  1. Перша декларація:

    char buf[10] = "";

    еквівалентно

    char buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  2. Друга декларація:

    char buf[10] = " ";

    еквівалентно

    char buf[10] = {' ', 0, 0, 0, 0, 0, 0, 0, 0, 0};
  3. Третя декларація:

    char buf[10] = "a";

    еквівалентно

    char buf[10] = {'a', 0, 0, 0, 0, 0, 0, 0, 0, 0};

Як бачимо, немає випадкового вмісту: якщо менше ініціалізаторів, решта масиву ініціалізується 0. Це так, навіть якщо масив оголошено всередині функції.


46
Ради людини, яка задає питання, варто зазначити, що стандарт C вимагає, щоб будь-яка частково повна ініціалізація масиву була залита нулем для решти елементів (компілятором). Це стосується всіх типів даних, а не лише char.
рисовий

4
@ouah, чому в кінці buf немає "\ 0"?
lkkeepmoving

14
@lkkeepmoving 0і '\0мають однакове значення.
оуа

1
@lkkeepmoving Ініціалізація та призначення є двома різними звірами, таким чином, C дозволяє надати рядок як ініціалізатор для масиву char, але забороняє призначення масивів (як сказав Ouah).
Лоренцо Донаті - Codidact.com

3
@Pacerier char buff[3] = "abcdefghijkl";недійсний. char p3[5] = "String";також є недійсним. char p[6] = "String";дійсний і такий же, як char p[6] = {'S', 't', 'r', 'i', 'n', 'g'};.
оуа

28

Редагувати: ОП (або редактор) мовчки змінив деякі одиничні цитати в початковому запитанні на подвійні лапки в якийсь момент після надання цієї відповіді.

Ваш код призведе до помилок компілятора. Ваш перший фрагмент коду:

char buf[10] ; buf = ''

є вдвічі незаконним. По-перше, в C немає такого поняття, як порожнє char. Ви можете використовувати подвійні лапки, щоб позначити порожній рядок, як при:

char* buf = ""; 

Це дасть вам вказівник на NULрядок, тобто односимвольну рядок із лише NULсимволом. Але ви не можете використовувати одинарні лапки, якщо всередині них нічого немає - це не визначено. Якщо вам потрібно призначити NULперсонажа, його потрібно вказати:

char buf = '\0';

Зворотна косої риси необхідно відмежовувати від характеру '0'.

char buf = 0;

виконує те саме, але колишній - це думка менш неоднозначне для читання, я думаю.

По-друге, ви не можете ініціалізувати масиви після їх визначення.

char buf[10];

оголошує і визначає масив. Ідентифікатор масиву bufтепер є адресою в пам'яті, і ви не можете змінити, куди bufвказується точка призначення. Так

buf =     // anything on RHS

є незаконним. Ваш другий та третій фрагменти коду з цієї причини незаконні.

Щоб ініціалізувати масив, потрібно зробити це під час визначення:

char buf [10] = ' ';

дасть вам 10-символьний масив, причому перший знак буде пробілом, '\040'а решта - NULтобто '\0'. Коли масив оголошується і визначається ініціалізатором, елементи масиву (якщо такі є) повз ті, з заданими початковими значеннями, автоматично додаються0 . Не буде "випадкового вмісту".

Якщо ви оголошуєте та визначаєте масив, але не ініціалізуєте його, як у наступному:

char buf [10];

у вас буде випадковий вміст у всіх елементах.


"Щоб ініціалізувати масив, ви повинні зробити це під час визначення ..." Це, і наступний рядок робить це краще, ніж прийнята відповідь.
Лорі Стерн

26
  1. Вони рівнозначні

    char buf[10] = "";
    char buf[10] = {0};
    char buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  2. Вони рівнозначні

    char buf[10] = " ";
    char buf[10] = {' '};
    char buf[10] = {' ', 0, 0, 0, 0, 0, 0, 0, 0, 0};
  3. Вони рівнозначні

    char buf[10] = "a";
    char buf[10] = {'a'};
    char buf[10] = {'a', 0, 0, 0, 0, 0, 0, 0, 0, 0};

8

Відповідна частина ініціалізації стандартного проекту C11 n1570 6.7.9 говорить:

14 Масив типу символів може бути ініціалізований літеральним рядком символів або літеральним рядком UTF-8, необов'язково укладеним у дужки. Послідовні байти рядкового літералу (включаючи закінчуючий нульовий символ, якщо є місце або якщо масив невідомого розміру) ініціалізують елементи масиву.

і

21 Якщо в списку, включеному дужкою, є менше ініціалізаторів, ніж у елементах або членах сукупності або менше символів у рядковому літералі, що використовується для ініціалізації масиву відомого розміру, ніж елементів у масиві, решта сукупності повинні ініціалізуватися неявно такими ж, як об'єкти, які мають статичну тривалість зберігання.

Таким чином, "\ 0" додається, якщо є достатньо місця , а решта символів ініціалізуються зі значенням, якеstatic char c; було б ініційовано у функції.

Нарешті,

10 Якщо об’єкт, який має тривалість автоматичного зберігання, не ініціалізується явно, його значення невизначене. Якщо об’єкт, який має статичну тривалість або тривалість зберігання, не ініціалізується явно, то:

[-]

  • якщо він має арифметичний тип, він ініціалізується на (позитивний або неподписаний) нуль;

[-]

Таким чином, charбудучи арифметичним типом, залишок масиву також гарантується ініціалізацією з нулями.


3

Цікаво, що масиви можна будь-яким чином ініціалізувати в будь-який час програми, за умови, що вони є членами structабо union.

Приклад програми:

#include <stdio.h>

struct ccont
{
  char array[32];
};

struct icont
{
  int array[32];
};

int main()
{
  int  cnt;
  char carray[32] = { 'A', 66, 6*11+1 };    // 'A', 'B', 'C', '\0', '\0', ...
  int  iarray[32] = { 67, 42, 25 };

  struct ccont cc = { 0 };
  struct icont ic = { 0 };

  /*  these don't work
  carray = { [0]=1 };           // expected expression before '{' token
  carray = { [0 ... 31]=1 };    // (likewise)
  carray = (char[32]){ [0]=3 }; // incompatible types when assigning to type 'char[32]' from type 'char *'
  iarray = (int[32]){ 1 };      // (likewise, but s/char/int/g)
  */

  // but these perfectly work...
  cc = (struct ccont){ .array='a' };        // 'a', '\0', '\0', '\0', ...
  // the following is a gcc extension, 
  cc = (struct ccont){ .array={ [0 ... 2]='a' } };  // 'a', 'a', 'a', '\0', '\0', ...
  ic = (struct icont){ .array={ 42,67 } };      // 42, 67, 0, 0, 0, ...
  // index ranges can overlap, the latter override the former
  // (no compiler warning with -Wall -Wextra)
  ic = (struct icont){ .array={ [0 ... 1]=42, [1 ... 2]=67 } }; // 42, 67, 67, 0, 0, ...

  for (cnt=0; cnt<5; cnt++)
    printf("%2d %c %2d %c\n",iarray[cnt], carray[cnt],ic.array[cnt],cc.array[cnt]);

  return 0;
}

1

Я не впевнений, але я зазвичай ініціалізую масив на "", у такому випадку мені не потрібно турбуватися про нульовий кінець рядка.

main() {
    void something(char[]);
    char s[100] = "";

    something(s);
    printf("%s", s);
}

void something(char s[]) {
    // ... do something, pass the output to s
    // no need to add s[i] = '\0'; because all unused slot is already set to '\0'
}

Не слід реально користуватися неявним правилом int . Ви повинні вказати тип для main()(і ви повинні використовувати void, тобто int main(void) { ... }. C99 позбулися цього правила, так що цей код не компілюватиметься для C99 і вище. Крім того , необхідно відзначити, що , починаючи з С99, якщо опустити returnв головне, є автоматичне return 0;розміщення / мається на увазі перед }головним кінцем. Ви використовуєте неявне правило int, яке працює лише до C99, але ви використовуєте неявне, returnщо працює лише з C99 і пізнішими ; ці два, очевидно, суперечливі .
RastaJedi
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.