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);
printf("%p\n", &s[0]);
printf("%p\n", &s[1]);
printf("%p\n", &s[2]);
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로 시작한다.