Heap 영역에서 malloc에 의해 메모리가 더 할당될수록, 화살표 방향으로 메모리의 범위가 커지게 됨
마찬가지로 스택 영역에서도 함수가 많이 호출될수록, 사용하는 메모리의 범위가 점점 위로 늘어남
이렇게 늘어나다 보면 제한된 메모리 용량 안에서 기존의 값을 침범하는 상황도 발생하는데 이를 힙 오버플로우 스택오버플로우라고 함
버퍼 오버플로우: 컴퓨터가 너무 많은 메모리를 써서 파일이나 사진이 열리지 않거나 화면이 정지하거나 아예 작동하지 않는 상황이 생기는 것 스택 오버플로우와 힙 오버플로우로 나뉨
스택 오버플로우: 스택 영역을 넘어 데이터가 저장되는 경우
- 함수의 재귀 호출이 무한 반복될 때, 스택 영역에 데이터가 계속해서 쌓이고 스택 영역을 넘어 데이터가 저장되면 프로그램이 종료
힙 오버플로우: malloc을 계속 호출해서 너무 많은 메모리를 할당해 메모리 속 다른 내용을 덮어쓰게 됨
사용자에게 입력 받기
cs50 라이브러리 없이 get_int를 구현해보기 [get_int 코드]
#include <stdio.h>
int main(void)
{
int x;
printf("x:");
scanf("%i",&x);
printf("x:%i\n",x);
}
scanf: 사용자로부터 형식 지정자에 해당되는 값을 입력받아 저장하는 함수
x의 주소를 scanf에게 주는 이유는 scanf 함수의 변수가 실제로 스택 영역 안에 x가 저장된 주소(&x)로 찾아가서 사용자가 입력한 값을 저장하도록 하기 위함
cs50 라이브러리 없이 get_int를 구현해보기 [get_int 코드]
#include <stdio.h>
int main(void)
{
char s[5];
printf("s:");
scanf("%s",s);
printf("s:%s\n",s);
}
s를 크기가 5인 문자열, 즉 크기가 5인 char 자료형의 배열로 저장했기 때문에 굳이 scanf에 s의 주소(%s)가 아닌 s를 입력해도 됨
clang 컴파일러는 문자 배열의 이름을 포인터로 다루기 때문에 scanf에 s라는 배열의 첫 바이트 주소를 넘겨주는 것
s는 크기가 5바이트인 배열로 저장했기 때문에 5개 이하는 무조건 출력이 됨
문자가 12까지는 출력이 되고 13이 넘어가게 되면 error가 나게 된다(궁금해서 직접 해봄)
파일 쓰기
사용자로부터 입력받아 파일에 저장하는 phonebook 프로그램도 작성할 수 있음
phonebook.c라는 파일을 만들고 이름과 전화번호부를 계속 추가할 수 있는 phonebook.csv 파일을 생성하는 코드 작성!
* csv란? (comma-separated values) 몇 가지 필드를 쉼표(,)로 구분한 텍스트 데이터 및 텍스트 파일
엑셀과 같은 행렬(matrix) 구조의 데이터를 표현/저장하기 쉽도록 정해 놓은 포맷
#include <stdio.h>
#include <string.h>
int main(void)
{ //Open file
FILE*file = fopen("phonebook.csv","a");
//Get strings from user
//편의를 위해 string 라이브러리에 있는 get_string 함수를 사용!
char*name = get_string("Name:");
char*number = get_string("Number:");
//Print (write) strings tp file
fprintf(file,"%s,%s\n",name,number);
//Close file
fclose(file);
}
FILE이라는 새로운 자료형을 가리키는 포인터 변수 file을 만들기. 즉 file은 변수의 이름이고 파일의 내용을 저장함
fopen 함수의 첫 번째 인자: 열고 싶은 파일의 이름, 두 번째 인자: r, w, a 중 하나(read, write, add)
사용자에게 name과 number라는 문자열을 입력받고,
fprint 함수를 이용해 printf에서처럼 파일에 직접 내용을 출력할 수 있음(컴파일 한 뒤에 이름과 번호를 적으면 phonebook.csv 파일에 정보가 추가됨!)
fclose 함수로 파일에 대한 작업을 종료해줘야 함
터미널에 입력할 때마다 phonebook.csv 파일에 업데이트됨
그냥 예시로 내가 혼자 해본 것..
#include <stdio.h>
int main(void)
{
float x;
printf("x:");
scanf("%f",&x);
printf("x:%.2f\n",x);
}
//./get long
//x:3.14
//x:3.14
파일 읽기
파일에 쓰는 프로그램을 작성했다면, 파일의 내용을 읽어서 파일의 형식이 JPEG 이미지인지 검사하는 프로그램 작성
#include <stdio.h>
int main(int argc, char *argv[])
{
//Ensure user ran program with two words at prompt
if (argc != 2)
{
return 1;
}
//Open file
FILE *file = fopen(argv[1], "r");
if (file == NULL)
{
return 1;
}
//Read 3 bytes from file
unsigned char bytes[3];
fread(bytes, 3, 1, file);
//Check if bytes are 0xff 0xd8 0xff
if (bytes[0] == 0xff && bytes[1] == 0xd8 && bytes[2] == 0xff)
{
printf("Maybe\n");
}
else
{
printf("No\n");
}
fclose(file);
}
*argc = arguments count로 main 함수에 전달된 인자의 개수
*argv = arguments vector로 가변적인 개수의 문자열, 프로그램이 시작됐을 때 넘겨받은 인자
main 함수를 보면 사용자로부터 입력을 받는 것이고 여기서는 파일의 이름을 입력으로 받음
만약 argc가 2가 아니라면, 파일명이 입력되지 않았거나 파일명 외의 다른 인자가 입력되었기 때문에 1(오류)를 리턴하고 프로그램을 종료함
만약 argc가 2면 프로그램이 그대로 진행됨
입력받은 파일명(argv [1])을 읽기'r'모드로 불러옴
만약 파일이 제대로 열리지 않으면 fopen 함수는 NULL을 리턴하기 때문에 file을 제대로 쓸 수 있는지를 검사하고, 아니면 1(오류)을 리턴하고 프로그램 종료함
만약 파일이 잘 열렸다면, 프로그램이 계속 진행됨
크기가 3인 문자 배열을 만들고, fread 함수를 이용해서 파일에서 첫 3바이트를 읽어 옴
fread 함수의 각 인자는 (배열, 읽을 바이트 수, 읽을 횟수, 읽을 파일)을 의미함
unsigned를 하는 이유는 0부터 255 범위의 값을 의미함
마지막으로 읽어 들인 각 바이트가 각각 0xFF, 0xD8, 0xFF 인지 확인
0xFF, 0xD8, 0xFF(255, 216, 255)는 JPEG 형식의 파일의 시작점에 꼭 포함되어 있어야 함(약속)
따라서 이를 검사하면 JPEG 파일인지 확인할 수 있음
https://everysmallstep.tistory.com/38
https://www.boostcourse.org/cs112/joinLectures/41307
지금까지 소소하게 느낀점
처음 시작할때부터 지금까지 많은 것을 배워온 느낌이다. 아직 강의 들은 것을 다 이해하지는
못하지만 계속 보다보면 익숙해져서 이해가 될 것 같다..
천천히 이해하려고 노력중인데 그래도 코드를 보는 것에는 조금 익숙해 진것도 같다..!
'cs > CS50' 카테고리의 다른 글
6: 자료구조-2(배열의 크기 조정하기) (0) | 2021.12.11 |
---|---|
6: 자료구조-1(malloc과 포인터 복습) (0) | 2021.12.11 |
5: 메모리-5(메모리 교환, 스택,힙) (0) | 2021.12.04 |
5: 메모리-4(메모리 할당과 해제) (0) | 2021.12.03 |
5: 메모리-3(문자열, 문자열의 비교와 복사) (0) | 2021.12.03 |