Ошибки при выделении памяти

1. Бывает ситуация, при которой память не может быть выделена. В данном случае функция malloc (и calloc) возвращает NULL. Потому, перед выделением памяти нужно обнулить указатель, а после выделения проверить, не равен ли он NULL. Так же ведёт себя и realloc. Когда мы используем функцию free инспектировать на NULL нет необходимости, потому что Ошибки при выделении памяти согласно документации free(NULL) не производит никаких действий. Применительно к последнему примеру:

?

#include #include #include #include #define TERM_WORD "end" #define SIZE_INCREMENT 10 void main() { char **words; char buffer[128]; unsigned wordCounter = 0; unsigned length; unsigned size = SIZE_INCREMENT; int i; if (!(words = (char**) malloc(size*sizeof(char*)))) { printf("Error Ошибки при выделении памяти: can't allocate memory"); getch(); exit(1); } do { printf("%d: ", wordCounter); scanf("%127s", buffer); if (strcmp(TERM_WORD, buffer) == 0) { break; } length = strlen(buffer); if (wordCounter >= size) { size += SIZE_INCREMENT; if (!(words = (char**) realloc(words, size*sizeof(char*)))) { printf("Error: can't reallocate memory"); getch(); exit(2); } } if (!(words[wordCounter] = (char*)malloc Ошибки при выделении памяти(length + 1))) { printf("Error: can't allocate memory"); getch(); exit(3); } strcpy(words[wordCounter], buffer); wordCounter++; } while(1); for (i = 0; i < wordCounter; i++) { printf("%s\n", words[i]); } getch(); for (i = 0; i < wordCounter; i++) { free(words[i]); } free(words); }

Хотелось бы добавить, что ошибки выделения памяти могут случиться, и просто выходить из приложения Ошибки при выделении памяти и выбрасывать ошибку плохо. Решение находится в зависимости от ситуации. К примеру, если не хватает памяти, то можно подождать некое время и после чего снова попробовать выделить память, либо использовать для временного хранения файл и переместить туда часть объектов. Либо выполнить чистку, сократив применяемую память и Ошибки при выделении памяти удалив ненадобные объекты.

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

?

#include #include #include void main() { int *p = NULL Ошибки при выделении памяти; if (!(p = (int*) malloc(100 * sizeof(int)))) { printf("Error"); exit(1); } //Изменили указатель p++; //Сейчас free не может отыскать метаданные об объекте free(p); //На неких компиляторах ошибки не будет getch(); }

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

3. Внедрение освобождённой области. Почему это работает в си, описано выше. Эта ошибка выливается в другую – так именуемые висящие указатели (dangling pointers либо wild pointers). Вы удаляете объект, но при всем этом забываете поменять значение указателя на NULL. В конечном итоге, он хранит адресок области памяти, которой Ошибки при выделении памяти уже нельзя пользоваться, при всем этом проверить, валидная эта область либо нет, у нас нет способности.

?

#include #include #include #define SIZE 10 void main() { int *p = NULL; int i; p = (int*) malloc(SIZE * sizeof(int)); for (i = 0; i < SIZE; i++) { p[i] = i; } free(p); for (i = 0; i < SIZE; i Ошибки при выделении памяти++) { printf("%i ", p[i]); } getch(); }

Эта программка отработает и выведет мусор, либо не мусор, либо не выведет. Поведение не определено.

Если же мы напишем

?

free(p); p = NULL;

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

4. Освобождение Ошибки при выделении памяти освобождённой памяти. Пример

?

#include #include void main() { int *a, *b; a = (int*) malloc(sizeof(int)); free(a); b = (int*) malloc(sizeof(int)); free(a); free(b); _getch(); }

Тут два раза вызывается free для переменной a. При всем этом, переменная a продолжает хранить адресок, который может дальше быть передан кому-нибудь Ошибки при выделении памяти для использования. Решение тут такое же по-прежнему - обнулить указатель очевидно после удаления:

?

#include #include void main() { int *a, *b; a = (int*) malloc(sizeof(int)); free(a); a = NULL; b = (int*) malloc(sizeof(int)); free(a);//вызов free(NULL) ничего не делает free(b); b = NULL; _getch Ошибки при выделении памяти(); }

5. Одновременная работа с 2-мя указателями на одну область памяти. Пусть, к примеру, у нас два указателя p1 и p2. Если под 1-ый указатель была выделена память, то 2-ой указатель может просто скомпрометировать эту область:

?

#include #include #include #define SIZE 10 void main() { int *p1 = NULL; int *p2 = NULL; size Ошибки при выделении памяти_t i; p1 = malloc(sizeof(int) * SIZE); p2 = p1; for (i = 0; i < SIZE; i++) { p1[i] = i; } p2 = realloc(p1, SIZE * 5000 * sizeof(int)); for (i = 0; i < SIZE; i++) { printf("%d ", p1[i]); } printf("\n"); for (i = 0; i < SIZE; i++) { printf("%d ", p2[i]); } _getch(); }

Разглядим код ещё раз.

?

int *p Ошибки при выделении памяти1 = NULL; int *p2 = NULL; size_t i; p1 = malloc(sizeof(int) * SIZE); p2 = p1;

Сейчас оба указателя хранят один адресок.

?

p2 = realloc(p1, SIZE * 5000 * sizeof(int));

А вот тут происходит неожиданное. Мы решили выделить под p2 новый участок памяти. realloc гарантирует сохранение контента, но вот сам указатель p Ошибки при выделении памяти1 может не быть валидным. Есть различные ситуации. Во-1-х, вызов malloc мог выделить много памяти, часть которой не употребляется. После вызова ничего не обменяется и p1 продолжит оставаться валидным. Если же потребовалось перемещение объекта, то p1 может указывать на невалидный адресок (конкретно это с большой вероятностью и произойдёт в нашем Ошибки при выделении памяти случае). Тогда p1 выведет мусор (либо же произойдёт ошибка, если p1 полезет в труднодоступную память), в то время как p2 выведет старенькое содержимое p1. В данном случае поведение не определено.

Дву указателя на одну область памяти это вообще-то не ошибка. Бывают ситуации, когда без их не обойтись. Но Ошибки при выделении памяти это еще одно минное поле для программера.


orientirovochnie-pokazateli-dlya-ocenki-bakterialnoj-obsemenennosti-stepeni-chistoti-vozduha-nekotorih-pomeshenij.html
orientirovochnie-sanitarno-zashitnie-zoni-predpriyatij-po-s-staroe-drozhzhanoe.html
orientirovochnie-temi-zachetnogo-sobesedovaniya.html