Почему C/C++ имеет проблему памяти?

Я считал много программистов, говорящих и пишущих при программировании в C/C++ существует много проблемы, связанной с памятью. Я планирую учиться программировать в C/C++. У меня есть знание новичка C/C++, и я хочу видеть некоторый краткий образец, почему C/C++ может иметь проблемы с управлением памятью. Обеспечьте некоторые образцы.

8
задан LinuxNewbie 5 June 2010 в 06:17
поделиться

9 ответов

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

Например, просто не освободить выделенную память. Например, это приведет к «двойному освобождению», при попытке освободить a дважды и не удастся освободить b :

char *a = malloc(128*sizeof(char));
char *b = malloc(128*sizeof(char));
b = a;
free(a);
free(b); // will not free the pointer to the original allocated memory.

Далее следует пример переполнения буфера, которое повреждает произвольную память. Это переполнение буфера, потому что вы не знаете, какова длина str . Если он длиннее 256 байт, он запишет эти байты где-нибудь в память, возможно, перезаписав ваш код, а возможно, и нет.

void somefunc(char *str) {
    char buff[256];
    strcpy(buff, str);
}
16
ответ дан 5 December 2019 в 04:41
поделиться

По сути, в этих языках вы должны вручную запрашивать каждый бит памяти, который не является локальной переменной, известной во время компиляции, и вручную освобождать его, когда он вам больше не нужен. Существуют библиотеки (так называемые умные указатели), которые могут в некоторой степени автоматизировать этот процесс, но они не везде применимы. Более того, нет абсолютно никаких ограничений на то, как вы можете (пытаетесь) получить доступ к памяти с помощью арифметики указателей.

Ручное управление памятью может привести к ряду ошибок:

  • Если вы забудете освободить память, произойдет утечка памяти
  • Если вы используете больше памяти, чем запросили для данного указателя, произойдет переполнение буфера.
  • Если вы освобождаете память и продолжаете использовать "висящий указатель" на нее, у вас неопределенное поведение (обычно программа аварийно завершается)
  • Если вы неправильно рассчитали арифметику указателей, у вас произойдет сбой или повреждение данных

И многие из этих проблем очень трудно диагностировать и отладить.

7
ответ дан 5 December 2019 в 04:41
поделиться

Причина, по которой это часто называют чем-то отличным от C / C ++, заключается в том, что многие современные языки выполняют управление памятью и сборку мусора. В C / C ++ это не так (к лучшему или к худшему). Вам необходимо вручную выделить и освободить память, и если это не сделать правильно, это приведет к утечке памяти, которая была бы невозможна на языке, который выполняет управление памятью за вас.

3
ответ дан 5 December 2019 в 04:41
поделиться

Одна из распространенных проблем управления памятью в C и C++ связана с отсутствием проверки границ массивов. В отличие от Java (например), C и C++ не проверяют, что индекс массива попадает в фактические границы массива. Из-за этого легко случайно перезаписать память. Например (C++):

char *a = new char[10];
a[12] = 'x';

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

3
ответ дан 5 December 2019 в 04:41
поделиться

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

Так зачем вам вручную управлять памятью, по нескольким причинам: --Чтобы понять, как это работает / чтобы - Чтобы реализовать сборку мусора / автоматическое управление памятью, вам необходимо вручную - С некоторыми вещами более низкого уровня, такими как ядро, вам нужна гибкость, которую может дать ручное управление памятью. - Самое главное, если вы правильно управляете памятью вручную, вы можете получить большое ускорение / снизить накладные расходы на память (лучшую производительность), связанную проблему со сборкой мусора (хотя она становится лучше по мере написания лучших сборщиков мусора, таких как jvm hotspot) заключается в том, что вы не можете контролировать управление памятью, поэтому сложно делать что-то в реальном времени (гарантируя крайние сроки для определенных целей, таких как автомобильные тормоза и кардиостимуляторы, попробуйте специальный gc в реальном времени), а программы, которые взаимодействуют с пользователями, могут немного зависнуть или лаг (отстой для игры).

Многие «современные C ++» (было сказано, что C ++ можно рассматривать как несколько языков в зависимости от того, как вы его используете), в отличие от c с классами (или функции x и y C ++), используют компромисс, часто использование простого необязательного gc / автоматического управления памятью (обратите внимание, что дополнительный gc может быть хуже в управлении памятью, чем обязательный, потому что, когда он является обязательным, это более простая система), а также некоторые функции ручного управления памятью. В зависимости от того, как вы это делаете, у него могут быть некоторые преимущества и недостатки использования gc и ручного управления памятью. Необязательный сборщик мусора также доступен с некоторыми библиотеками C, но с C он встречается реже, чем с C ++.

1
ответ дан 5 December 2019 в 04:41
поделиться

Я могу честно сказать, что у меня нет "проблем" с распределением памяти при программировании на C++. Последний раз утечка памяти произошла более 10 лет назад и была вызвана слепой глупостью с моей стороны. Если вы пишете код, используя RAII, контейнеры стандартной библиотеки и небольшую толику здравого смысла, проблемы действительно не существует.

5
ответ дан 5 December 2019 в 04:41
поделиться

Я планирую научиться программировать на C / C ++

Что именно вы имеете в виду? Вы хотите научиться программировать на C или хотите научиться программировать на C ++? Я бы не рекомендовал изучать оба языка одновременно.

С точки зрения пользователя управление памятью в C ++ намного проще, чем в C, поскольку большая часть памяти инкапсулирована классами, например std :: vector . С концептуальной точки зрения, можно утверждать, что управление памятью в C намного проще. По сути, есть только malloc и free :)

5
ответ дан 5 December 2019 в 04:41
поделиться

Когда new используется для получения блока памяти, размер, зарезервированный операционной системой, может быть больше, чем ваш запрос, но никогда не меньше. Из-за этого и того факта, что удаление не сразу возвращает память в операционную систему, когда вы проверяете всю память, которую использует ваша программа, вас могут заставить поверить, что ваше приложение имеет серьезные утечки памяти. Поэтому проверка количества байтов, используемых всей программой, не должна использоваться как способ обнаружения ошибок памяти. Вы можете подозревать утечку памяти только в том случае, если диспетчер памяти указывает на большой и непрерывный рост используемой памяти.

2
ответ дан 5 December 2019 в 04:41
поделиться

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

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

struct student
{
 char name[20];
 int roll;
 float marks;
}s[100];

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

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

struct student *s;

s=(struct student *)malloc(sizeof(struct student));

scanf("%s %d %f",s->name,s->roll,s->marks);

, если он не используется, удалите его из временного пространства.

free(s);

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

2
ответ дан 5 December 2019 в 04:41
поделиться