5. 메모리

최준영·2021년 8월 25일
0

CS50

목록 보기
5/6

16진수


  • 컴퓨터 과학에서는 숫자를 16진수로 표현하는 경우가 많다.
  • 앞에 0x를 붙혀 16진수임을 알린다.
  • 2진수를 사용하는데, 2개의 16진수는 1byte의 2진수로 변환되기 때문에 정보를 표현하기 유용하다.

메모리 주소


  • 어떤 변수를 선언, 초기화 한 후 그 변수가 저장되어었는 메모리의 주소를 알고싶다면 &연산자를 사용하면 된다. print("%p\n", &n); 형식 지정자는 %p를 사용한다.
  • 위의 코드를 사용하면 0x123fea34와 같이 16진법으로 표현된 주소값을 얻을 수 있다.

포인터


  • '*주소'를 사용하면 해당 메모리 주소에 있는 실제 값을 얻을 수 있다.
  • int \*p=&n식은 *p라는 포인터 변수에 변수 n의 주소를 저장한다는 의미이다.

문자열


  • 문자열 변수는 문자열의 가장 첫번째 문자를 가리키는 포인터이다.
  • 'string 변수'는 'char *변수'로 쓸 수 있다.

문자열 비교


int main(void)
{
  char *s = "EMMA";
  printf("%p\n", s); // 첫번째글자(E) 주소 출력
  printf("%p\n", &s[0]); // 첫번째글자(E) 주소 출력
  printf("%p\n", &s[1]); // 두번째글자(M) 주소 출력
  printf("%p\n", &s[2]); // 세번째글자(M) 주소 출력
  
  printf("%c\n", *s); // 첫번째 글자 출력
  printf("%c\n", *(s+1)); // 두번째 글자 출력
  printf("%c\n", *(s+2)); // 세번째 글자 출력
  printf("%c\n", *(s+3)); // 네번째 글자 출력
}
  • *(변수 + n)에서 n을 하나씩 증가시키면 바로 옆에 있는 문자를 선택할 수 있다.
  • 문자열 간에 ==를 사용한 비교는 주소를 비교하는 것이기 때문에 예상한 결과값이 아닐 수 있다.

문자열 복사


string s = "emma";
string t = s;

t[0] = toupper(t[0]);
  • 위의 식에서 t만 변경했지만, s도 같이 변경된다. t에 s와 동일한 주소를 저장했기 때문에 발생하는 일이다.

메모리 할당과 해제


  • 참조 현상을 발생하지 않게 하려면 t에게 메모리 할당함수 malloc을 사용하여 새로운 메모리를 할당하고 그 곳에 저장하면 된다
char *s = get_string("s: ");
char *t = malloc(strlen(s) + 1);

for (int i = 0, n = strlen(s); i < n + 1; i++)
{
    t[i] = s[i];
}
  • s 문자열 길에에 널 종단문자(\0)에 해당하는 1을 더한만큼 메모리를 할당한다.
  • malloc 함수를 이용하여 메모리를 할당한 후에는 free라는 함수를 이용하여 메모리를 해제해줘야 한다.
  • 해제하지 않으면 메모리에 저장한 값을 쓰레기값으로 남게되어 메모리 용량의 낭비가 발생한다. 이를 메모리 누수라고 한다.
  • valgrind라는 프로그램을 사용하면 메모리 문제를 쉽게 확인할 수 있다.
  • 버퍼 오버플로우란 배열의 인덱스를 벗어나는 값으로 배열에 접근하면 발생하는 에러이다.

메모리 교환, 스택, 힙


#include <stdio.h>

void swap(int *a, int *b);

int main(void)
{
    int x = 1;
    int y = 2;

    printf("x is %i, y is %i\n", x, y);
    swap(&x, &y);
    printf("x is %i, y is %i\n", x, y);
}

void swap(int *a, int *b)
{
    int tmp = *a;
    *a = *b;
    *b = tmp;
}
  • 사용자 지정 함수를 사용해서 값을 교환하려면 포인터 개념을 이용해야한다.
  • void swap(int a, int b){}로 할 경우 a와 b를 교환하더라도 x와 y는 교환이 이루어지지 않는다.

메모리 구조

  • 머신 코드 영역에서는 프로그램이 실행될 때 그 프로그램이 컴파일된 바이너리가 저장된다.
  • 글로벌 영역에는 프로그램 안의 전역 변수가 저장된다.
  • 힙 영역에는 malloc으로 할당된 메모리의 데이터가 저장된다. 메모리 범위가 아래로 늘어난다.
  • 스택에는 프로그램 내의 함수와 관련된 것들이 저장된다. 메모리 범위가 위로 늘어난다.
  • 힙과 스택이 점점 늘어나다보면 제한된 용량 하에서 기존의 값을 침범하는 상황도 발생하는데, 이를 힙 오버플로우 또는 스택 오버플로우라고 한다.

scanf


  • scanf : 사용자로부처 형식 지정자에 해당되는 값을 입력받아 저장하는 함수이다. 두번째 인자는 변수의 주소를 기입한다.
scanf("%s", s);
scanf("%i", &n);

파일 쓰기


  • 사용자로부터 입력을 받아 파일에 저장하는 프로그램을 작성할 수 있다.
  • fopen이라는 함수를 이용하면 파일을 FILE이라는 자료형으로 불러올 수 있다.
  • fopen 함수의 첫번째 인자는 파일의 이름, 두번째 인자는 모드로 r은 읽기, w는 쓰기, a는 덧붙이기를 의미한다.
 FILE *file = fopen("phonebook.csv", "a");
 char *name = get_string("Name: ");
 char *number = get_string("Number: ");
 fprintf(file, "%s,%s\n", name, number);
 fclose(file);
  • fprintf 함수를 이용하여 printf에서처럼 파일에 직접 내용을 출력할 수 있다.
  • 작업이 끝난 후에는 fclose함수로 파일을 닫아주어야 한다.

파일 읽기


  • fread(배열, 읽을 바이트 수, 읽을 횟수, 읽을 파일)을 사용하여 파일을 입력받을 수 있다.
  • JPEG형식의 파일은 바이트가 0xFF, 0xD8, 0xFF로 시작한다.
profile
do for me

0개의 댓글