일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 로버트 C마틴
- 클린코드다시읽기
- 에릭노이먼
- 출처는 코딩애플
- 쏙쏙 들어오는 함수형코딩
- 생코님Redux
- 쏙쏙들어오는함수형코딩
- 출처 : https://www.boostcourse.org/
- 출처 : 한입크기로 잘라먹는 타입스크립트
- 쏙속 들어오는 함수형코딩
- 리엑트를 다루는 기술
- 에릭 노이먼
- 에릭 노먼드
- 출처 : 코딩앙마
- https://product.kyobobook.co.kr/detail/S000001952246
- 유틸리티타입은 공식문서 자주 보자
- 이웅모
- 고등애플
- 쏙쏙 들어오는 함수형 코딩
- 큰돌의 CS책
- 출처 : 코딩애플
- 김영한쌤
- 출처 : 자바스크립트 딥다이브
- 흥달쌤
- 갈길이 멀구나
- 출처는 코딩앙마
- 함수형 코딩
- 자바스크립트 딥다이브
- 나는 flux좋아...
- 오종택개발자님
- Today
- Total
흰둥씨의 개발장
[모두를 위한 컴퓨터 과학(CS50 2019)] 메모리 본문
1) 메모리 주소
0 1 2 3 4 5 6 7 8 9 A B C D E F => 16진수 (Hexadecimal)
ㄴ컴퓨터에서는 16진수를 많이 씀
ㄴ2진수로 표현하면 너무 길어서, 처리할 때 16진수가 유용
ㄴ0x는 그냥 붙여서 0x뒤에 오는 문자나 숫자가 16진수임을 알려줌
#include <stdio.h>
int main(void)
{
int n = 50;
printf("%p\n", &n); //&n는 'n의 주소'를 의미하는 연산자 , %p는 주소출력해줌
printf("%i\n", *&n); //&n앞에 붙은 *은 그 주소의 값으로 접근해달라는 의미
//만약 변수의 자료형을 모른다면 어쨌든 뭐든 지정해줘야함
}
2) 포인터
ㄴ변수는 메모리 주소를 저장하고 있고, 변수의 값은 변수가 저장한 메모리주소에 저장되어있음
ㄴ포인터는 변수가 저장한 메모리 주소를 가리킴 (그 메모리 주소로가면 값을 찾을수있어!)
#include <stdio.h>
int main(void)
{
int n = 50;
int *p = &n; //포인터 변수 p에 n의 주소값을 저장
//p앞에 붙은 *는 '포인터'의미로 이 포인터가 int타입의 변수를 가리킨다는 의미
printf("%p\n", p); //포인터 P값인 n의 주소 출력
printf("%i\n", *p); //포인터 p가 가리키는 메모리주소의 값을 출력
}
3) 문자열
ㄴC에서는 문자열이라는 타입이 없음, 여러 문자 묶음을 추상화 한 것
#include <stdio.h>
#include <cs50.h>
int main(void)
{
string s = "EMMA"; //s라는 변수는 문자배열의 첫번째 바이트'E'의 메모리 주소만을 저장함
//문자열은 char의 나열, 마지막 바이트에는 \0을 저장해서 끝을 알려줌
char *p = "EMMA"; //string s와 같음
//왜냐하면, 문자열이라는 것은 어떤 char의 주소를 저장하고 있는 변수이기 때문에
//string은 char *과 같음
//C에는 문자열이라는 타입이 없음
printf("%s\n", s); // EMMA
printf("%s\n", p); // EMMA
printf("%p\n", p); // 포인터 변수이기 때문에 메모리 주소 출력됨
printf("%p\n", &p[0]); // p[0]의 메모리 주소 , 위와 같은 주소 출력됨
printf("%p\n", &p[1]); // p[1]의 메모리 주소 (1바이트씩 차이 남)
printf("%p\n", &p[2]); // p[2]의 메모리 주소
printf("%p\n", &p[3]); // p[3]의 메모리 주소
}
- 문자열이 없기 때문에 아래와 같이 정의해서 사용할 수 있음
ㄴtypedef는 새로운 자료형을, char *은 문자에 대한 포인터를, string은 자료형의 이름을 의미
typedef char *string
4) 문자열 비교
#include <stdio.h>
int main(void)
{
char *s = "EMMA";
printf("%p\n", s); //s의 메모리 주소값 출력
printf("%c\n", *s); //E s의 1번째 값 출력
printf("%c\n", *(s+1));//M s의 2번째 값 출력
printf("%c\n", *(s+2));//M s의 3번째 값 출력
printf("%c\n", *(s+3));//A s의 4번째 값 출력
}
#include <cs50.h>
#include <stdio.h>
int main(void)
{
// 사용자로부터 두 개의 문자열 입력받아 s와 t 변수에 저장
string s = get_string("s: ");
string t = get_string("t: ");
// 두 문자열을 비교
if (s == t)
{
printf("Same\n");
}
else
{
printf("Different\n");
}
}
ㄴ위와 같이 입력하면 s와 t에 똑같은 문자열을 입력해도 Different를 출력함
ㄴ아래와 같이 배열의 값을 하나씩 순회하는 식을 짜면 잘 작동함
#include <cs50.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
// 사용자로부터 두 개의 문자열 입력받아 s와 t 포인터 변수에 저장
char *s = get_string("s: ");
char *t = get_string("t: ");
if(strlen(s) != strlen(t)) //s와 t의 길이가 같지 않으면
{
printf("Different");
return 0;
}
// 두 문자열을 비교
for(int i = 0; i < strlen(s) ; i++) //문자열 길이비교를 했기 때문에 i < strlen()을 사용가능
{
if (*(s+i) != *(t+i)) //s와 t값을 순회하며 비교해서 같지 않으면
{
printf("Different\n");
return 0;
}
}
printf("Same\n"); //같지 않은 부분 없으면
}
5) 문자열 복사
사용자에게 문자값을 입력받아서, s에 저장하고, t에 s를 복사한뒤, t의 첫글자만 uppercase로 변환해서 출력하기
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
char *s = get_string("s: "); //사용자에게 문자를 입력받아서
char *t = malloc(strlen(s) + 1); //malloc()은 함수는 정해진 크기 만큼 메모리를 할당하는 함수
//t에 입력받은 문자s 복사함 널종단문자까지 복사하기 위해 +1
for (int i = 0, n = strlen(s); i < n + 1; i++) // 널종단문자까지 복사함
{
t[i] = s[i];
}
t[0] = toupper(t[0]);
printf("s: %s\n", s);
printf("t: %s\n", t);
}
변수는 초기화 되지 않으면 쓰레기 값
6) 메모리 할당과 해제
malloc의 반대 함수는 free함수
ㄴ메모리가 부족해지 않으려면 사용하지 않는 메모리 free해줘야 함
ㄴ멜록을 쓰면 프리를 해야한다
(...)
int main(void)
{
char *s = get_string("s: "); //사용자에게 문자를 입력받아서
char *t = malloc(strlen(s) + 1); //malloc()은 함수는 정해진 크기 만큼 메모리를 할당하는 함수
(...)
printf("s: %s\n", s);
printf("t: %s\n", t);
free(t)
}
어디에서 메모리 누수가 나는지 알고 싶다면 아래와 같은 명령어 활용
help50 valgrind ./파일명
#include <stdlib.h>
void f(void)
{
int *x = malloc(10 * sizeof(int)); //int가 10개 들어갈 배열 x
//x[10] = 0; x의 길이가 10개이기 때문에 x[0] ... x[9]까지 존재
//배열의 경계를 넘어서 까지 접근하는 것 '버퍼 오버플로우'
x[9] = 0;
free(x); //메모리 누수 해결
}
int main(void)
{
f();
return 0;
}
7) 메모리 교환, 스택, 힙
메모리 안에는 데이터 저장되는 구역이 나뉘어져 있음
ㄴ메모리 공간 제일 위에는 머신코드 그아래는 전역변수 저장함 그아래는 heap영역, 제일 아래는 stack으로 이루어짐
ㄴheap영역에는 malloc으로 할당된 메모리의 데이터가 저장(힙영역은 아래로 영역넓힘)
ㄴstack영역에는 프로그램 내의 함수와 관련된 것(지역변수...)들이 저장(stack영역은 위로 영역 넓힘)
아래 함수는 main에서 x와 y에 할당된 값을 swap함수를 호출해서 서로 바꾼후 다시 printf하는 식
#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); //swap함수를 호출했음에도
printf("x is %i, y is %i\n", x, y); //x,y는 바뀌지 않음
//because... 함수로 x와 y를 전달하면, 값을 복사해서 가져가기 때문에
}
void swap(int a, int b)
{
int tmp = a; //tmp에 a값을 넣어두고
a = b; //b값를 변수 a에 할당한뒤
b = tmp; //변수 b에 tmp의 값을 할당해서 swap
}
ㄴ위 함수 main에 있는 변수 x, y가 stack의 제일아래 위치, 그 위에 swap의 변수 a,b,tmp가 위치하게 됨(서로 저장 위치가 다름)
ㄴswap함수에게 x와 y의 값을 전달하는 것이 아닌, x와 y의 주소를 전달해서 값을 바꾸도록 하면 해결가능
ㄴswap 함수에서 int a가 x를 가리키고, int b가 y를 가리키도록 처리
#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); //x is 1, y is 2
swap(&x, &y); //x와 y의 주소 전달
printf("x is %i, y is %i\n", x, y); //x is 2, y is 1
}
void swap(int *a, int *b) //정수의 주소를 받아서 a와 b로 정의
{
int tmp = *a; //tmp에 a의 메모리주소안에 있는 값을 넣어두고
*a = *b; //b의 메모리주소안에 있는 값를 변수 a에 할당한 뒤
*b = tmp; //변수 b에 tmp의 값을 할당해서 swap
}
8) 파일쓰기
힙 오버플로우 : malloc이 너무 많아져서 기존값을 침범
스택 오버플로우 : 함수가 많이 호출되어 사용하는 메모리 범위가 기존값을 침범
scanf 함수 : 사용자로부터 형식 지정자에 해당되는 값을 입력받아 저장하는 함수
사용자에게 정수값을 받는 get_int함수
#include <stdio.h>
int get_int(void)
{
int x;
printf("x: ");
scanf("%i", &x); //int로 입력받아 x주소로 할당
//get_long이나 get_float는 scanf의 형식지정자를 %ld, %f로 지정해주면 됨
printf("x: %i\n", x);
}
사용자에게 문자열을 입력받는 get_string 함수
#include <stdio.h>
int get_string(void)
{
char s[5]; // 크기가 5인 char배열 , char *s = NULL;은 메모리공간이 할당되지 않아 값을 받을수 없음
printf("s: ");
scanf("%s", s);
printf("s: %s\n", s);
}
사용자로부터 이름, 전화번호 입력을 받아 csv파일로 저장하는 프로그램
ㄴfopen 함수는 파일을 FILE이라는 자료형으로 불러올 수 있음
ㄴfopen 함수의 첫번째 인자는 파일의 이름, 두번째 인자는 모드로 r은 읽기, w는 쓰기, a는 덧붙이기를 의미
ㄴfprintf 함수를 이용하여 파일에 직접 내용을 출력함(phonebook.csv파일안에 출력)
ㄴ작업이 끝난 후에는 fclose함수로 파일에 대한 작업을 종료
#include <cs50.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
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);
}
9) 파일읽기
주어진 파일이 jpeg인지 아닌지 검사
ㄴfopen이나 malloc, get_string같은 함수는 에러가 생기면 NULL을 반환함 (=>fopen 이 반환한 값 == NULL인지 검사)
ㄴJPEG파일의 첫 3개의 바이트는 무조건 FF, D8, FF로 시작함 (JPEG개발자들이 정한 매직넘버로, JPEG라는 것을 알려주려고 만듦)
#include <stdio.h>
int main(int argc, char *argv[]) //정수와 문자열 입력받음
{
if (argc != 2) //인자를 2개 입력했는지 검사
{
return 1;
}
FILE *file = fopen(argv[1], "r"); //입력받은 파일명(argv[1])을 ‘읽기(r)’로 불러옴
if (file == NULL) //file이 에러 나면
{
return 1;
}
unsigned char bytes[3]; //크기가 3바이트인 문자 배열
//unsigned는 0 ~ 255 범위의 값을 의미
fread(bytes, 3, 1, file); //fread(배열, 읽을 바이트수, 읽을 횟수, 읽을 파일) 파일에서 첫 3바이트를 읽어옴
if (bytes[0] == 0xff && bytes[1] == 0xd8 && bytes[2] == 0xff) //읽은 바이트가 JPEG파일매직넘버랑 일치하는지 체크
{
printf("Maybe JPEG\n");
}
else
{
printf("No\n");
}
fclose(file); //종료
}
'[오늘의 공부] > CS' 카테고리의 다른 글
[algorithm] 재귀 (feat. 하노이탑) (0) | 2023.09.13 |
---|---|
[algorithm] 배열 / 연결리스트 / 스택 / 큐 / 덱 (0) | 2023.08.13 |
[모두를 위한 컴퓨터 과학(CS50 2019)] 알고리즘 (0) | 2023.06.19 |
[모두를 위한 컴퓨터 과학(CS50 2019)] 배열 (0) | 2023.06.17 |
[모두를 위한 컴퓨터 과학(CS50 2019)] compile / debug / style (0) | 2023.06.17 |