C Language Basic

C Language [핵심정리] - 13

cCcode 2021. 5. 18. 22:11

1. 메모리 사용하기 - 2

malloc 함수로 할당한 메모리에 값을 저장할 때는 포인터역참조한 뒤 값을 저장하면 됩니다. 마찬가지로 해당 값을 출력할 때는 포인터역참조하여 값을 가져오면 됩니다.

역참조로 동적할당 된 메모리에 값을 저장
결과

결과만 본다면 아무런 문제가 없어보입니다. 하지만 또 경고를 표시하는 녹색 줄이 보이네요. 저 경고는 [C6011: NULL 포인터 'numPtr'을(를) 역참조하고 있습니다.]라는 경고 입니다. 이 경고가 생긴 이유는 malloc 함수항상 성공하는 함수가 아니기 때문입니다. 시스템에 메모리가 부족하거나 메모리 할당 조건이 맞지 않는 경우에 malloc 함수는 NULL을 반환하게 됩니다. 그래서 malloc 함수NULL을 반환하는 경우 해당 코드에 오류가 날수 있기 때문에 미리 경고하는 겁니다. 이 녹색 줄이 표시되는 걸 해결하고 싶다면 다음과 같이 NULL이 발생할 상황대비해야합니다.

예외 처리

이처럼 코드를 구성하면 NULL이 발생한 포인터를 사용하지 않아 경고가 뜨지 않습니다.

 

포인터를 역참조한 뒤 값을 할당할 때 memset 함수(memory set)를 사용하면 메모리의 내용을 원하는 크기만큼 특정 값으로 설정할 수 있으며, 이 때 설정하는 크기byte 단위 입니다. [memset 함수는 <string.h>파일에 선언되어 있습니다.]

• memset(포인터, 설정할 값, 크기); - 값 설정이 끝난 포인터를 반환합니다.

memset 사용 - 1
memset 사용 - 2

memset 함수는 주로 13줄처럼 설정한 값을 0으로 지정하여 메모리의 내용을 모두 0으로 만들 때(= 초기화 할 때) 사용합니다. memset 함수에 설정할 크기를 지정할 때는 12줄에서처럼 직접적으로 값을 주는 것보다 sizeof 연산자를 사용하는 경우가 많습니다. 왜냐하면 동적할당할 때도 메모리sizeof(int)만큼 할당했으니 설정할 크기도 sizeof(int)만큼 해야겠죠. 다만 여기서 주의해야 할 점이 크기를 지정할 때 sizeof(int *)처럼 포인터의 크기로 지정하면 안됩니다. 왜냐하면 포인터의 크기메모리 주소크기일 뿐 실제 메모리가 차지하는 크기가 아닙니다. 아,, 그리고 memset 함수는 메모리를 1byte 단위초기화합니다. 그래서 크기에 상관없이 일정한 결과값01byte 크기char 자료형을 사용하는 걸 권장드립니다. 이외에 자료형들은 우리가 원하는 값으로 세팅할 수 없기 때문이죠.

 

+ 우리가 흔히 부르는 쓰레기 값은 변수, 배열을 선언하거나 메모리할당하면 사용이 끝난 메모리를 다시 사용하게 됩니다. 쓰레기 값은 이전에 메모리를 사용할 때 저장된 값을 뜻하며 메모리를 다시 사용하는 시점에서는 필요없는 값이므로 쓰레기 값이라고 부릅니다. 따라서 변수, 배열을 선언하거나 메모리를 할당하면 쓰레기 값이 다시는 사용되지 않도록 초기화 해야합니다.

 

2. 배열 사용하기 

배열을 선언할 때는 다음과 같은 형식을 사용합니다. 

배열 선언

배열을 선언하면서 값을 초기화할 때는 { }(중괄호)안 값의 개수배열 크기보다 크면 안됩니다. 또한 중괄호를 이용한 값의 할당선언할 때만 사용할 수 있으며 이미 선언된 배열에는 사용할 수 없습니다. 배열에 값이 저장된 공간요소(element)라고 합니다. 배열에서 각 요소접근하려면 [ ](대괄호)를 사용해 각 요소의 인덱스지정해주면 됩니다. 

인덱스 지정
배열 선언후 인덱스로 접근

여기서 배열의 인덱스는 항상 0부터 시작합니다. 따라서 배열 numArr첫 번째 요소는 항상 인덱스[0]이 됩니다. 하지만 5줄, 그러니까 선언할 때 사용한 [ ](대괄호)값인덱스가 아닌 크기이기 때문에 1부터 시작합니다. 입문자분들은 종종 헷갈려서 배열의 크기잘못 설정하거나 잘못된 인덱스 접근하는 분도 계십니다. 다시 한번 말씀드리지만 절대로 선언할 때 명시해준 크기와 인덱스를 헷갈리시면 안됩니다. 

+ 배열의 인덱스0부터 시작하는 이유는 메모리 주소0부터 시작하기 때문입니다. 

 

배열을 선언과 동시에 초기화 할때만 배열 크기를 생략할 수 있습니다.

크기 생략
크기를 생략할 수 있는 경우

 

3. 배열을 초기화 하기

배열초기화하는 방법에는 3가지가 있습니다.

1) 중괄호를 사용하여 0으로 초기화 하기

중괄호 사용

2) 반복문을 사용하여 0으로 초기화 하기

반복문 사용(크기만큼 반복한다)
결과

3) memset 함수를 사용해 0으로 초기화한다.

memset 함수 사용
결과

 

요소에 값 할당

이처럼 배열은 대괄호요소에 접근한 후 값을 할당할 수 있습니다. 그런데 배열 요소를 벗어난 인덱스로 접근하면 어떻게 될까요..?

잘못된 인덱스로 접근
결과

잘못된 인덱스로 접근했을 때 컴파일 에러는 발생하지 않지만 쓰레기 값이 출력됩니다. 즉, 배열의 범위를 벗어난 접근을 하면 배열이 아닌 다른 메모리 공간 접근하게 됩니다.

 

만약 여러분이 반복문으로 크기가 5인 배열의 요소를 모두 출력한다고 가정해봅시다.

배열 요소 모두 출력

그런데 갑자기 배열의 크기를 7로 늘려야 하는 상황이 생겼습니다. 그래서 배열의 크기7로 늘렸지만 정신없는 나머지 반복문의 조건식 수정해야하는 걸 잊어버린겁니다.

배열 요소 수정 O, 조건식 수정 X

버그는 이럴 때 발생합니다. 이 경우 실수를 방지하기 위해선 배열의 크기가 바뀌어짐에 따라 배열의 크기도 알아서 계산하는 코드를 만들어야 합니다. 그래서 이미 선언된 배열의 크기(요소 개수)는 어떻게 알수 있을까요?

배열 요소의 개수는 배열이 차지하는 전체공간에서 요소의 크기로 나누어줍니다.

배열 요소 개수 구하는 과정
결과

왜냐하면 numArr은 자료형이 int형요소 7개 모여있는 배열이기 때문에 int(4byte) × 7 = 28byte가 되는 겁니다.

그래서 우리가 배열 요소의 개수 즉, 배열의 크기를 구하는 과정은 저 식을 역으로 계산한 것일 뿐입니다.

 

C언어는 인덱스배열의 범위를 벗어났는지 검사하지 않습니다. 그래서 프로그래머는 항상 이를 염두에 두고 코드를 작성해야 하죠. 그 방법 중 하나로 배열의 크기를 구해놓고, 배열에 접근하기전에 인덱스가 (요소 개수 - 1)을 넘지 않는 지 확인하는 것도 좋은 방법입니다.

인덱스가 범위를 벗어났는지 확인
결과