메모리 주소, 포인터
C에서는 변수의 메모리상 주소를 받기 위해 '&’이라는 연산자를 사용.
#include <stdio.h>
int main(void)
{
int n = 50;
printf("%p\\n", &n);
}
예를 들어, 위와 같은 코드를 실행하면 ‘0x7ffe00b3adbc’와 같은 값을 얻을 수 있고, 이는 변수 n의 16진법으로 표현된 메모리의 주소이다.(보안상 실행시 위치가 매번 바뀜)
반대로 '*'를 사용하면 그 메모리 주소에 있는 실제 값을 얻을 수 있다.
16진수의 유용성
16진수(Hexadecimal)로 표현하면 2진수로 표현했을 때 보다 훨씬 간단해지고 컴퓨터는 8개의 비트가 모인 바이트 단위로 정보를 표현하므로 2개의 16진수는 2진수로 변환되기 때문에 정보를 표현하기 매우 유용하다.
64bits 시스템에서는 8Bytes(1Byte = 8bit)가 1 word로 처리, 32bits ⇒ 4Bytes가 1word)
포인터 변수
포인터 = 메모리 주소를 값으로 가지는 변수(다른 변수를 가리키는 변수) 는 프로그래밍 언어에서 다른 변수 혹은 그 변수의 메모리 공간주소를 가리키는 변수를 말한다. 포인터가 가리키는 값을 가져오는 것을 역참조(dereferencing)라고 한다.
#include <stdio.h>int main(void)
{
int n = 50;
int *p = &n;
printf("%p\\n", p);
printf("%i\\n", *p);
}
*p라는 포인터 변수에 &n 이라는 값, 즉 변수 n의 주소를 저장.
printf("%p\n", p)는 변수 n의 주소를 출력, printf("%i\n", *p)는 n의 변수 n의 값을 출력(역참조).
실제 컴퓨터 메모리에서 저장되는 변수 p(int *p = &n;)
위 그림과 같이 실제로 p의 값, 즉 n의 주소값을 생각하지 않고, 추상적으로 단지 p가 n을 가리키고 있다는 것만 생각해도 된다.
위 그림과 같이 실제로 p의 값, 즉 n의 주소값을 생각하지 않고, 추상적으로 단지 p가 n을 가리키고 있다는 것만 생각해도 된다.
메모리 교환, 스택, 힙
메모리 안에는 데이터를 저장하는 구역이 나뉘어져 있다.
▷ 머신 코드 영역(machine code) - 프로그램이 실행될 때 그 프로그램이 컴파일된 바이너리(0,1)가 저장된다.
▷ 글로벌 영역(globals) - 프로그램 안에서 저장된 전역 변수가 저장된다.
▷ 힙 영역(heap) - malloc으로 할당된 메모리의 데이터가 저장된다. ⇒ 메모리 해제(free) 해주어야 함.
사용자가 직접 관리할 수 있는 ‘그리고 해야만 하는’ 메모리 영역 => 사용자에 의해 메모리 공간이 동적으로 할당되고 해제된다.
메모리의 낮은 주소에서 높은 주소의 방향으로 할당된다.
heap overflow = malloc을 계속 호출해 너무 많은 메모리를 할당해 메모리 속 다른 내용을 덮어씀.
▷ 스택(stack) - 프로그램 내의 함수와 관련된 것들(지역 변수, 매개변수)이 저장됩니다.
스택 영역은 함수의 호출과 함께 할당되며, 함수의 호출이 완료되면 소멸한다.
스택 프레임(stack frame) = 스택 영역에 저장되는 함수의 호출 정보
스택 영역은 푸시(push) 동작으로 데이터를 저장하고, 팝(pop) 동작으로 데이터를 인출한다.
이러한 스택은 후입선출(LIFO, Last-In First-Out) 방식에 따라 동작하므로, 가장 늦게 저장된 데이터가 가장 먼저 인출된다.
스택 영역은 메모리의 높은 주소에서 낮은 주소의 방향으로 할당된다.
stack overflow = 자기 자신을 계속해서 호출해 메모리가 가득참.
buffer overflow = 메모리가 가득차 프로그램이 정지되거나 아예 동작하지 않음.
위 그림처럼 힙 영역과 스택 영역의 메모리가 반대방향으로 할당되기 때문에 메모리가 가득 차게 되면 덮어쓰게 된다.
#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;
}
swap을 이용해 x, y의 값을 바꾼다.
a, b, x, y, tmp 모두 스택 영역에 저장된다. 하지만 서로 다른 위치에 저장되어 있는 변수이므로 a와 b를 바꾸고 싶다면 a, b 각각을 x와 y를 가리키는 포인터로 지정해야 한다.
<메모리에 대해 새롭게 알게된 점>
- 단순 칸칸이 네모가 아니라 메모리 영역별 각각 저장하는 위치가 다르다.(효율적으로 메모리를 관리할 수 있음)
- string은 사실 없다. 밑 예시와 같이 char *t = malloc(strlen(s) + 1);으로 char 글자를 malloc 메모리 할당해준 것이다. +1은(끝나는 지점을 알려주는 \n 공간)
- 메모리가 할당되면 해제해주어야 한다. free(t);
- NULL은 메모리가 할당되지 않았다는 의미.
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
char *s = get_string("s: ");
char *t = malloc(strlen(s) + 1);
strcpy(t, s);
t[0] = toupper(t[0]);
printf("%s\\n", s);
printf("%s\\n", t);
free(t);
}
csv => 쉼표로 분리된 값(, seperate the values)
간단한 엑셀이나 Numbers같은 프로그램으로 열 수 있는 파일
+) 최근 Python으로 웹 스크랩핑을 배우면서 구직 정보를 csv파일에 저장해봤는데 데이터를 저장할 때 ,(쉼표) 에 따라 행이 달라지기 때문에 , 유의하면서 데이터를 다뤄야했다. 데이터를 잘 정리하기만 하면 굉장히 깔끔히 데이터를 저장할 수 있어 csv 너무 편했다.
강사님도 너무 열정적이시고 학생들을 불러 직접 시연하며 보여주시기도 해 설명이 쏙쏙 들어온다. 평소에 코딩하면서 궁금했던 점들을 이 강의를 통해 정말 많이 알 수 있었다. C언어도 처음 접했는데 Low-level programming language를 알고나니 다른 언어들이 더 잘 이해가 간다. 컴퓨터처럼 생각하는 사고를 배운다고 생각하면서 가볍게 들어도 큰 도움이 될 것이다. 컴퓨터 프로그래밍 입문자분들에게 넘넘 강추하는 cs50! 부스트코스나 유튜브에서 무료로 수강할 수 있습니다.
참고 사이트
http://www.tcpschool.com/c/c_memory_structure
※ 공부하면서 정리한 글입니다. 문제가 있을시 알려주세요.
'개발 지식 > CS' 카테고리의 다른 글
시간 복잡도 - 대표적인 빅오(Big-O) 표기법 (0) | 2023.02.18 |
---|---|
[CS]컴퓨터 주요 구성 요소(CPU, Memory, IO Devices, System Bus), 메모리 계층과 각 메모리 특징 (0) | 2023.01.14 |
[cs50 모두를 위한 컴퓨터 과학] 자료구조(Data Structure) (0) | 2022.10.02 |
[cs50 모두를 위한 컴퓨터 과학] 알고리즘(Algorithm) (0) | 2022.08.04 |