Символьный массив в C

Когда мы определяем символьный массив как 'символьное имя [10]', указывает это, что массив 'имя' может содержать строку длины десять символов. Но в программе, показанной ниже массива, имя может содержать больше чем десять символов. Как это возможно?

//print the name of a person.  
char name[10];  
scanf("%s",name);  
printf("%s",name);  

Здесь, если я ввожу имя даже длины, больше, чем десять символов, нет никакой ошибки периода выполнения, и программа печатает все символы, которые я ввел. Существует завершение программы, если я ввожу имя двадцати или больше символов.

Примечание: Я запускаю программу на Ubuntu9.04 с помощью gcc компилятора.

5
задан sepp2k 11 July 2010 в 18:59
поделиться

9 ответов

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

scanf("%9s", name);

Это позволит прочитать до 9 символов и добавить завершающий символ NUL, итого 10 символов.

Что произойдет, если вы не ограничите количество символов, которые может прочитать scanf? Ну, тогда ваша строка окажется перезаписанной. В данном случае, я полагаю, ваш буфер находится в стеке, поэтому вы перезаписываете что-то в стеке. В стеке хранятся локальные переменные, адреса возврата (к функции, которая вызвала эту функцию) и аргументы функции. Теперь злоумышленник может заполнить этот буфер произвольным кодом и перезаписать адрес возврата адресом этого кода (существует множество вариантов этой атаки). Злонамеренный пользователь может выполнить произвольный код через эту программу.

3
ответ дан 18 December 2019 в 09:05
поделиться

Потому что scanf не знает, какой длины массив. Переменная "name" имеет тип не "массив", а "указатель" (или "адрес"). Это говорит: начните писать здесь и продолжайте писать, пока не закончите. Возможно, вам повезет, и в вашем стеке окажутся другие не столь важные вещи, которые будут перезаписаны, но в конце концов scanf будет писать, писать и писать, и перезапишет что-то фатальное, и вы получите Segmentation Fault. Вот почему вы всегда должны передавать размер массивов.

Это похоже на то, как если дать слепому человеку карандаш и сказать: "Начинай писать здесь", при этом он не видит, где конец бумаги. В конце концов они напишут на столе и что-нибудь повредят. (Примечание: это не оскорбление слепых, это просто метафора.)

В приведенном выше случае я настоятельно рекомендую использовать fgets() для получения определенной суммы из stdin, а затем sscanf() для извлечения любой информации из этой строки и помещения ее в отдельные переменные по мере необходимости. Scanf() и fscanf() - это зло, я никогда не находил для них применения, которое не могли бы более безопасно решить fgets()+sscanf().

char line[1024]; /* arbitrary size */
if( fgets( line, 1024, stdin ) != NULL )
{
  fprintf( stdout, "Got line: %s", line );
}

Или для вещей за пределами строк:

# cat foo.c
  #include <stdio.h>
  int main( int argc, char **argv )
  {
    int i;
    char line[1024];
    while( fgets( line, 1024, stdin ) != NULL )
    {
      if( sscanf( line, "%d", &i ) == 1 )
      { /* 1 is the number of variables filled successfully */
        fprintf( stdout, "you typed a number: %d\n", i );
      }
    }
  }
# gcc foo.c -o foo
# ./foo
  bar
  2
  you typed a number: 2
  33
  you typed a number: 33
  <CTRL-D>
7
ответ дан 18 December 2019 в 09:05
поделиться

В массиве размером 10 символов для представления строки на языке C вы действительно можете использовать только 9 символов и завершающий символ нулем. Если вы используете более 9 символов (+1 завершение), то у вас будет неопределенное поведение.

Вы просто перезаписываете память, чего быть не должно. То, что происходит, будь то segfault или работа, как вы ожидаете, так же хорошо, как и случайное.

4
ответ дан 18 December 2019 в 09:05
поделиться

Добро пожаловать в мир C...

  • C не выполняет проверку границ массива;
  • имя массива - это не что иное, как указатель на первый элемент массива;
  • scanf (как использовано в примере программы Mohit) не обрабатывает ограничение размера буфера назначения;
  • с неправильным значением указателя вы можете писать в любом месте памяти, и вам следует ожидать непредсказуемого поведения, ошибки сегментации, если вам повезет.
2
ответ дан 18 December 2019 в 09:05
поделиться

В C нет проверок на длину массива. Это позволит вам переполнить массив.

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

Попробуйте этот код и посмотрите, что произойдет, если вы введете более 10 символов.

char name[10];
char name2[10];  
scanf("%s",name);  
printf("%s",name);  
printf("%s",name2); 

Также массив имен может содержать 9 символов, десятым должен быть завершающий нулевой ноль '\0'

1
ответ дан 18 December 2019 в 09:05
поделиться

Как это возможно?

Массив выделяется на стеке. За ним может быть пустое пространство или данные, которые имеют меньшее значение, чем национальная безопасность (например, регистры callee-saves, которые фактически не используются в вызывающей программе). В конце концов, если введенное вами имя достаточно длинное, вы перезапишете что-то важное. В том числе, в некоторых компиляторах, обратный адрес!

Запуск программы под valgrind мгновенно обнаружит ошибку превышения.

1
ответ дан 18 December 2019 в 09:05
поделиться

Вы эксплуатируете неопределенное поведение, поэтому может произойти все, что угодно - программа может дать сбой, или продолжить работу, или начать делать что-то странное.

0
ответ дан 18 December 2019 в 09:05
поделиться

Когда вы говорите char c[10], вы выделяете 10 байт для этой переменной. Однако, ваша программа может "владеть" и последующими байтами, поэтому вы можете не получить segfault. Но вы столкнетесь с таким количеством других проблем, что пожалеете, что не получили segfault.

0
ответ дан 18 December 2019 в 09:05
поделиться

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

scanf () и gets () имеют точно такую ​​же проблему с переполнением памяти. Вы можете легко прочитать больше символов, чем может вместить ваш char [] .

0
ответ дан 18 December 2019 в 09:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: