기술나눔

C 언어를 처음부터 배우기 33 - 메모리 관리 (1)

2024-07-12

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

1. 기본 상황
C 언어의 메모리 관리는 시스템 관리와 ​​프로그래머 사용자 매뉴얼 관리의 두 부분으로 나누어집니다. 시스템이 관리하는 메모리는 주로 함수 내부의 변수(로컬 변수)입니다. 변수 중 이 부분은 함수가 실행될 때 메모리 영역에 들어갑니다. , 운영 체제는 자동으로 메모리에서 이를 언로드합니다. 사용자가 수동으로 관리하는 메모리는 주로 프로그램이 실행되는 전 과정에 걸쳐 존재하는 변수(전역변수)이다. 이 부분이 위치한 메모리 영역을 "힙 영역"이라고 한다. 사용자에 의해. 사용 후 해제하는 것을 잊은 경우 프로그램이 종료될 때 운영 체제로 넘겨질 때까지 메모리를 계속 점유합니다.
2. 무효 포인터
컴퓨터의 메모리 공간에는 고유한 주소 코드가 할당되어 있으며, 지정된 메모리 영역은 메모리 포인터를 통해 찾을 수 있습니다. 포인터 변수는 유형을 가져야 합니다. 예를 들어 int* p=&x;는 정수 변수 x의 주소를 가리키는 int 유형 포인터를 선언합니다. 컴파일러는 이 주소에서 데이터를 가져올 때 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은 int*로 수신할 수 있는 void*를 반환하므로 코드를 더 쉽게 이해할 수 있습니다.
지침:
a. malloc 함수를 사용하여 포함합니다.<stdlib.h>헤더 파일(예:<stdio.h> 컴파일은 잘 되지만 제대로 실행되지 않습니다. 이 점을 염두에 두세요.
b. ptr에 값을 할당합니다: *ptr=1000;.
c. free(나중에 접하게 될)와 함께 malloc을 사용하세요.
d. Malloc은 주소 할당에 성공하지 못할 수 있습니다. 따라서 처리를 위해 if 문을 추가할 수 있습니다.
e. malloc은 초기화와 상관없이 메모리만 할당합니다. 초기화가 필요한 경우 다른 함수를 호출해야 합니다.
f. malloc이 가장 일반적으로 사용되는 경우는 배열 및 사용자 정의 데이터 구조에 메모리를 할당하는 것입니다.
2、memset()
기능: 포인터가 가리키는 메모리 블록의 각 바이트에 초기값을 할당합니다.
매개변수: 매개변수 1 대상 메모리를 가리키는 포인터 매개변수 2 할당 내용(int 유형 ASCII 코드 값 또는 char 유형 문자) 매개변수 3 할당할 바이트 수(size_t 유형)
반환 값: 대상 메모리를 가리키는 포인터를 반환합니다. 매개변수 1과 동일하게 수신하는 것은 의미가 없습니다.
사용법: memset(ptrDestMem,'A',sizeof(char)*1024) //길이가 1024바이트인 메모리 블록의 각 바이트에 문자 A를 할당합니다.
지침:
a. 이 함수가 속한 헤더 파일은 다음과 같습니다.<string.h> , 일부 컴파일러는 이 헤더 파일을 포함하지 않아도 정상적으로 사용할 수 있습니다. 실행 오류가 발생하면 포함하십시오.
b. memset은 바이트(비트가 아님)에 대한 작업입니다. 매개변수 3은 할당해야 하는 바이트 수를 나타내며, 이는 대상 메모리의 바이트 수보다 작거나 같을 수 있지만 제한을 초과할 수는 없습니다.
c. 매개변수 2의 값은 1바이트(int 유형 255)가 수용할 수 있는 값을 초과할 수 없습니다.
2、free()
기능: malloc과 짝을 이루는 함수로, malloc 함수에 의해 할당된 메모리를 해제하고 메모리 누수를 방지하는 데 사용됩니다.
매개변수: malloc 함수에 의해 반환된 포인터
사용법: 무료(ptr);
지침:
a. free를 사용할 때 포함해야 하는 헤더 파일도 있습니다.<stdlib.h> , 잊지 마세요.
b. free 함수는 한 번만 실행할 수 있으며 동일한 메모리 주소를 반복적으로 해제할 수 없으며 해제된 포인터를 다시 사용할 수 없습니다.
c. 먼저 malloc과 free를 쌍으로 작성하고, 잊어버리지 않도록 중간에 다른 코드를 삽입하는 것이 가장 좋습니다.
3. realloc()
re는 다시 alloc 할당 약어를 의미하며 함께 메모리 재할당을 의미합니다.
기능: 할당된 메모리 블록의 크기를 수정합니다(증가 또는 감소).
매개변수: 매개변수 1, 원본 메모리 블록 포인터, 매개변수 2, 증가 또는 감소 후 메모리 블록 크기(still size_t 유형)
반환값 : void* 포인터 (원래 포인터형 변수로 받을 수 있음)
사용법: void* newPtr=realloc(ptr,sizeof(int)*10);
지침:
a. realloc 기능을 사용할 때 이 기능도 포함되어야 합니다.<stdlib.h> .
b. 원래 포인터가 가리키는 메모리 블록이 새 포인터로 대체되었으므로 프로그램이 종료되면 새 포인터를 해제해야 합니다. 그렇지 않으면 작업 오류가 발생합니다.
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. }