OriginalGriff
Цитата:
Если я изменю char x[30] на char *x и char y[10] на char *y ,то почему компилятор попал в ошибку?
Это становится немного сложным для новичка, но вот идет ... Я постараюсь быть с тобой помягче!
Существует два типа памяти, которые использует программа на языке Си:
Heap
и
Stack
.
Куча-это огромный блок памяти, который выделяется переменной, когда вы специально запрашиваете его с помощью
malloc
функция, и это ваша ответственность, чтобы освободить его, когда вы закончите использовать
free
- если вы этого не сделаете, то вы получите проблему, называемую "утечкой памяти", когда ваша программа просто продолжает захватывать все больше и больше памяти, которую она больше не использует. В крайних случаях это может привести к сбою вашего приложения или системы.
Стек-это гораздо меньший блок памяти, который выделяется каждому из них.
thread
(подумайте о приложении как о потоке, это не совсем точно, но на данный момент это будет сделано). И когда я говорю "намного, намного меньше", я серьезно: в то время как
Heap
может использоваться вся физическая память вашего компьютера плюс все свободное место на жестком диске ad "виртуальная память", a
Stack
редко бывает больше 1 МБ. Он содержит все переменные, которые являются локальными для функции, а также все "обратные адреса", которые сообщают вашему приложению, куда "вернуться", когда оно возвращается из функции. Каждый элемент (обычно 32 бита данных, то есть целое число или четыре символа) занимает одно "место" в стеке, точно так же, как монеты в реальном стеке: вы добавляете их сверху, и вы можете только удалить их сверху, потому что попытка взять их из середины похожа на чрезмерную амбициозность в Дженге - все это падает! :смеяться:
Когда вы вызываете функцию, система помещает обратный адрес в стек, а затем добавляет достаточно места для всех локальных переменных: в вашем случае 40 байт для двух массивов (хотя на практике она, вероятно, выделит 32 байта для первого и 12 для второго только для того, чтобы они начинались и заканчивались на границе слова - это все упрощает).
Вы тогда позвоните
strcpy2
и он делает то же самое: стеки обратного адреса выделяют пространство для двух параметров указателя (хотя на практике они, вероятно, теперь будут вообще памятью, но используют регистры внутри процессора).
strcpy2
затем копирует символы из одного указателя в другой - перезаписывая все, что там было с самого начала. А поскольку это стек, то если адресату не хватает места, он не замечает или даже не заботится об этом и перезаписывает все, что может найти - в данном случае обратный адрес, который сообщит системе, где возобновить выполнение
main
когда функция заканчивается.
Он добирается до конца функции, берет обратный адрес, который вы только что переписали обратно из стека, и пытается выполнить код там - и поскольку это больше не является допустимым местоположением программы, вы получаете ошибку, и ваше приложение падает.
Есть ли в этом смысл? Это трудно объяснить без картинок ... :смеяться:
OriginalGriff
Да - может быть!
Это выделяет память в виде кучи, но не предотвращает повреждение памяти, если Источник больше места назначения - это просто создает ошибки, которые гораздо труднее отследить! :смеяться:
Вероятно, вам следует передать параметр "limit", который указывает, сколько символов будет скопировано - точно так же, как это делает strncpy:
https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rtref/strncpy.htm
Это не предотвращает проблему (единственный способ сделать это-выделить "новое пространство" в методе копирования, а затем вы столкнетесь с утечкой памяти позже, если не будете осторожны), но это уменьшает ее до "управляемых пропорций".
Почему вы изучаете язык Си в 2020 году? сейчас это очень старый язык, и, как правило, есть гораздо лучшие из них!