Nick_is_asking Ответов: 3

C - вопрос о копировании массивов(я не понимаю)


Привет.У меня есть код на языке Си,который я копирую из одного массива в другой.
Почему я могу скопировать массив x в массив y?
массив x имеет <= 30 символов, а y - <= 10.
Почему компилятор не попадает в ошибку?

Код:

Что я уже пробовал:

#include <stdio.h>

void strcpy2(char *s, char *d);

int main(void)
{   char x[30] = "abijngjnhtdjgibhbicdef";
    char y[10];
    strcpy2(x, y);
    printf("%s", y);
 }
 
 void strcpy2(char *s, char *d) 
 {   
    while (*s != '\0')
    {
        *d = *s;
        s++;
        d++;
    }
   *d = '\0';
}

3 Ответов

Рейтинг:
2

F-ES Sitecore

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


Nick_is_asking

ООО, хорошо, теперь я понимаю.
Если я изменю char x[30] на char *x и char y[10] на char *y ,то почему компилятор попал в ошибку?
Спасибо.

Рейтинг:
2

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 когда функция заканчивается.
Он добирается до конца функции, берет обратный адрес, который вы только что переписали обратно из стека, и пытается выполнить код там - и поскольку это больше не является допустимым местоположением программы, вы получаете ошибку, и ваше приложение падает.


Есть ли в этом смысл? Это трудно объяснить без картинок ... :смеяться:


Nick_is_asking

Хорошо,я кое-что понимаю,потому что в этом семестре у меня есть ассамблея и С.
Итак, я заметил, что мне нужно написать char *y = malloc(sizeof(char) * 50), чтобы получить
50 * (1 байт) = 50 байт памяти
и тогда все будет хорошо.

OriginalGriff

Да - может быть!
Это выделяет память в виде кучи, но не предотвращает повреждение памяти, если Источник больше места назначения - это просто создает ошибки, которые гораздо труднее отследить! :смеяться:

Вероятно, вам следует передать параметр "limit", который указывает, сколько символов будет скопировано - точно так же, как это делает strncpy:

https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rtref/strncpy.htm

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

Почему вы изучаете язык Си в 2020 году? сейчас это очень старый язык, и, как правило, есть гораздо лучшие из них!

Рейтинг:
1

Patrice T

Цитата:
Почему компилятор не попадает в ошибку?

Потому что в C, вы несете ответственность за все Компилятору не нужно ничего проверять.