Инициализация массива символов C

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]будет случайный контент?

lkkeepmoving
источник
2
Что ж, мой компилятор не принимает ваш (исправленный) код: «тип массива 'char [10]' не назначается».
Martin R
@MartinR теперь будет работать ...
lkkeepmoving
1
@lkkeepmoving: char buf[10]; buf = "a";вовсе не компилировать. - Пожалуйста , попробуйте сначала, а затем копировать / вставить фактический код в вопрос. Это сэкономит вам и всем читателям вашего вопроса уйму работы.
Martin R
@MartinR Извините за это. Я думал, что могу назначить buf [] последним, но, похоже, нет. Теперь код работает.
lkkeepmoving 08

Ответы:

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. Это так, даже если массив объявлен внутри функции.

ouah
источник
47
Для человека, задающего вопрос, стоит указать, что стандарт C требует, чтобы любая частично полная инициализация массива дополнялась нулем для остальных элементов (компилятором). Это касается всех типов данных, а не только char.
падди
4
@ouah, почему в конце buf [] нет символа "\ 0"?
lkkeepmoving 08
14
@lkkeepmoving 0и '\0имеют то же значение.
Оуа 08
1
@lkkeepmoving Инициализация и присваивание - это два разных зверя, поэтому C позволяет вам предоставить строку в качестве инициализатора для массива символов, но запрещает присваивания массивов (как сказал 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'};.
ouah
28

Изменить: OP (или редактор) молча изменил некоторые одинарные кавычки в исходном вопросе на двойные кавычки в какой-то момент после того, как я предоставил этот ответ.

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

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;
}
user3381726
источник
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 и более поздних версий. Также следует отметить, что, начиная с C99, если вы опустите returnв main, есть автоматическое return 0;размещение / подразумевается перед }концом main. Вы используете неявное правило int, которое работает только до C99, но вы используете неявное, returnкоторое работает только с C99 и более поздними версиями ; эти два явно противоречат .
RastaJedi