Недавно я ответил на вопрос здесь, в SO, где проблема заключалась в том, чтобы ввести несколько предложений кода и распечатать его. Мой код такой:
#include<stdio.h>
int main() {
clrscr();
int line, i;
char (*string)[100];
printf("How many line?\n");
scanf("%d",&line);
getchar();
for(i=0;i<line;i++) {
gets(string[i]);
}
printf("You entered:\n");
for(i=0;i<line;i++) {
puts(string[i]);
}
return 0;
}
Как видите, я не выделил никакой памяти для отдельных строк, т.е. s[0]
,s[1]
, ……. но, что удивительно, мой компилятор не дал мне никаких предупреждений или ошибок об этом, и он работает отлично.
Поэтому я разместил этот код и, честно говоря, получил немало отрицательных отзывов за него (я знаю, что заслужил это). Можете ли вы объяснить, почему этот код работает и не дает ошибки сегментации?
Мой вывод такой, как показано:
char (*string)[100];
в порядке, string
представляет указатель на 100 char
, но он не инициализирован. Следовательно, он представляет собой произвольный адрес. (Хуже того, он не обязательно представляет один и тот же произвольный адрес при последующем обращении.)
gets(string[i]);
Хм, это считывает данные со стандартного ввода в блок памяти, начиная со случайного адреса, плюс i*100
До тех пор, пока не будет прочитан байт NUL.
Не очень крепкий. Также не гарантируется выдача ошибки. Если вы не получили его, случайный адрес должен быть сопоставлен с записываемыми байтами.
Как видите, я не выделил никакой памяти для отдельных строк, т.е.
s[0]
,s[1]
но удивительно, мой компилятор не дал мне никаких предупреждений или ошибок за это, и это работает отлично.
Время уменьшить ваши ожидания или повысить уровень диагностики компилятора. Пытаться -Wall -Wextra
, если он принимает варианты в этом стиле. Должен предупредить вас, что string
используется без предварительной инициализации. Предупреждение о том, что gets
было бы не рекомендуется, но мой компилятор не упоминает об этом.
C и C ++ позволяют вам управлять памятью самостоятельно. Вы несете ответственность за проверку указателей. В Си это главный источник проблем.
В C ++ решение состоит в том, чтобы использовать альтернативы указателям, такие как ссылки (которые нельзя инициализировать) и умные указатели (которые управляют памятью за вас). Хотя вопрос помечен как C ++ и компилируется как программа C ++, он написан не в стиле, который называется C ++.