Обмен технологиями

Изучите язык C с нуля 33 - Управление памятью (1)

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

1. Основная ситуация
Управление памятью языка C разделено на две части: управление системой и управление руководством пользователя программиста. Память, управляемая системой, в основном представляет собой переменные (локальные переменные) внутри функции. Эта часть переменных попадает в память во время работы функции. Эта часть области памяти становится «областью стека» после завершения функции. , операционная система автоматически выгружает его из памяти. Память, управляемая пользователем вручную, представляет собой в основном переменные (глобальные переменные), которые существуют на протяжении всего процесса работы программы. Область памяти, в которой расположена эта часть, называется «областью кучи». Эти переменные необходимо вручную освободить из памяти. пользователем. Если вы забудете освободить его после использования, он будет продолжать занимать память до тех пор, пока не будет передан операционной системе при выходе из программы.
2. недействительный указатель
Пространству памяти компьютера присвоен уникальный адресный код, и указанную область памяти можно найти по указателю памяти. Переменные-указатели должны иметь тип, например: int* p=&x объявляет указатель типа int, который указывает на адрес целочисленной переменной x. Когда компилятор получает данные по этому адресу, он знает, что тип int. данные сохраняются. Если вы не уверены, какой тип данных хранится, и просто хотите сначала найти адрес блочной памяти, используется указатель типа void. Указатель типа void также называется указателем неопределенного типа и может указывать на любой тип данных.
Указатели типа void могут быть преобразованы в указатели других типов, и в их использовании нет ничего особенного, за исключением того, что сохраненный контент нельзя проанализировать с помощью метода «*».
int x = 10 //Объявляем целочисленную переменную x;
void* p = &x; //Объявляем указатель void и указываем адрес x, указывая, что указатель int (&x) преобразуется в указатель void.
int* q = p // указатель void преобразуется обратно в целочисленный указатель
printf( "%in", *q //Результат выполнения: 10);
Обратите внимание на разницу между void* и void: void* не имеет типа, и когда он используется для объявления функции, это означает, что возвращаемое значение отсутствует, а void*, хотя и не имеет типа, но имеет указатель, что-то возвращает;
3. Функции, связанные с управлением памятью
1. malloc()
Эту функцию можно запомнить отдельно. m — сокращение памяти, а alloc — сокращение выделения. Вместе они выделяют память.
Функция: подать заявку на непрерывный блок памяти из области кучи (напоминание: память области кучи должна управляться программистом и должна быть уничтожена после использования. Это всегда следует помнить. Формат использования: malloc (см. 1);
Параметры: Параметр 1 — это размер блока памяти (неотрицательное целое число типа size_t, возвращаемое значение sizeof имеет этот тип).
Возвращаемое значение: указатель void* (мы будем использовать любой тип указателя, который используем для получения выделенной памяти)
Использование: Переменные, объявленные с помощью функции malloc, находятся в области кучи, поэтому часто используется метод анонимного объявления, то есть вместо использования метода адреса конкретных переменных, malloc напрямую возвращает указатель, как показано ниже:
int* ptr = (int*) malloc(sizeof(int)); //В области кучи объявляется переменная-указатель int.
Принудительное преобразование в круглых скобках не требуется. malloc возвращает void*, который можно получить с помощью int*. Сильное преобразование упрощает понимание кода.
Меры предосторожности:
а. Используйте функцию malloc для включения.<stdlib.h>заголовочный файл, например, содержит только<stdio.h> Он компилируется нормально, но не работает должным образом, имейте это в виду.
б. Присвойте значение ptr: *ptr=1000;.
в. Используйте malloc в сочетании с free (с которым вы столкнетесь позже).
d. Возможно, Malloc не удалось выделить адреса. Если это не удалось, он вернет NULL. По этой причине для обработки можно добавить оператор if.
e. malloc только выделяет память, независимо от инициализации. Если требуется инициализация, необходимо вызвать другую функцию.
е. Чаще всего malloc используется для выделения памяти для массивов и пользовательских структур данных.
2、memset()
Функция: Присвойте начальное значение каждому байту в блоке памяти, на который указывает указатель.
Параметры: Параметр 1 Указатель, указывающий на целевую память. Параметр 2 Содержимое назначения (тип int, значение кода ASCII или символ типа char). Параметр 3 Количество назначаемых байтов (тип size_t).
Возвращаемое значение: Возвращает указатель, указывающий на целевую память. Получать бессмысленно, как и параметр 1.
Использование: memset(ptrDestMem,'A',sizeof(char)*1024) //Назначаем символ A каждому байту блока памяти длиной 1024 байта
Меры предосторожности:
a. Заголовочный файл, которому принадлежит эта функция:<string.h> , некоторые компиляторы можно использовать без включения этого заголовочного файла. Если возникает ошибка, включите его.
б. Обратите внимание, что memset — это операция с байтами (а не битами); параметр 3 указывает, сколько байтов необходимо назначить, что может быть меньше или равно количеству байтов в целевой памяти, но не может превышать предел.
c. Значение параметра 2 не может превышать то, что может вместить один байт (тип int 255). Если оно превышает это значение, оно не может быть записано.
2、бесплатно()
Функция: функция в паре с malloc, используемая для освобождения памяти, выделенной функцией malloc, и предотвращения утечек памяти.
Параметры: указатель, возвращаемый функцией malloc.
Использование: бесплатно(ptr);
Меры предосторожности:
а. Файлы заголовков, которые необходимо включить при использовании бесплатного ПО, также являются.<stdlib.h> , не забывай.
б. Функция освобождения может быть выполнена только один раз, и один и тот же адрес памяти не может быть освобожден повторно, а освобожденный указатель не может быть использован снова.
c. Лучше всего сначала написать malloc и free парами, а затем вставить другие коды в середину, чтобы не забыть.
3.realloc()
re, что опять же означает аббревиатуру выделения памяти, вместе означает перераспределение памяти.
Функция: изменить размер выделенного блока памяти (увеличить или уменьшить).
Параметры: параметр 1, исходный указатель блока памяти, параметр 2, размер блока памяти после увеличения или уменьшения (все еще тип size_t)
Возвращаемое значение: указатель void* (может быть получен переменной типа исходного указателя)
Использование: void* newPtr=realloc(ptr,sizeof(int)*10);
Меры предосторожности:
а. При использовании функции realloc ее также необходимо включить.<stdlib.h> .
б. Блок памяти, на который указывает исходный указатель, был заменен новым указателем, поэтому при завершении программы должен быть освобожден новый указатель, а исходный указатель освобождать не нужно, иначе возникнет ошибка операции. происходить.
c. Realloc может не выделить память и вернуть NULL в случае неудачи, поэтому лучше добавить оператор if, чтобы справиться с этим.
4. Примеры применения

  1. #include<stdio.h>
  2. #include<stdlib.h> //malloc、free、realloc
  3. #include<string.h> //memset
  4. int main(void)
  5. {
  6. //A void指针的使用
  7. float PI = 3.14159;
  8. void* pPI = &PI;
  9. float r = 2.5;
  10. printf("半径2.5圆的面积:%fn", r * r * *(float*)pPI);//*(float*)pPI—pPI强转为float指针后再解出指向的值
  11. //B malloc、memset、free函数使用
  12. int n = 8;
  13. void* pMyMem = malloc(sizeof(char)*n); //char占1字节,malloc分派n字节的内存,返给void指针
  14. if (pMyMem == NULL)return 0; //若分派内存失败,程序结束
  15. void* myMem2=memset(pMyMem,'B',sizeof(char)*8); //对malloc分派的内存区块个字节都写入字符'B'。
  16. //并用myMem2接收返回的指针
  17. if (pMyMem == myMem2)printf("memset写入区块指针与其返回的指针相同n");
  18. char* transCh = pMyMem; //将void指针转成char型指针
  19. printf("显示写入内容:");
  20. for (int i = 0; i < n; i++)
  21. {
  22. printf("%c ", *transCh); //显示写入的字符
  23. transCh++;
  24. }
  25. printf("n");//换行
  26. free(pMyMem); //释放malloc函数分派的内存
  27. //free(ch); //只有malloc分派的内存才需要释放,且只释放一次(这里会报错)
  28. //C realloc、free函数的使用
  29. int* pMem = malloc(sizeof(int)*5);
  30. if (pMem == NULL)return 0;
  31. for (int i = 0; i < 5; i++) pMem[i] = (i+1)*10;
  32. for (int i = 0; i < 5; i++) printf("%i ", pMem[i]);
  33. printf("n重新增加分派内存后n");
  34. int* newpMem = realloc(pMem, sizeof(int) * 10);
  35. if (newpMem == NULL)return 0;
  36. for (int i = 0; i < 10; i++) newpMem[i] = (i + 1) * 10;
  37. for (int i = 0; i < 10; i++)printf("%i ", newpMem[i]);
  38. free(newpMem); //释放realloc的内存
  39. //free(pMem);//pMem已被重置,不能再释放,此语句会造成运行失败
  40. getchar(); //暂停屏幕
  41. return 0;
  42. }