C언어 배열 초기화 null - ceon-eo baeyeol chogihwa null

C언어 배열 초기화 null - ceon-eo baeyeol chogihwa null

우리는 일반적으로 배열의 선언과 동시에 초기화를 합니다. 이유는? 저 방식이 편하니까...

C언어 배열 초기화 null - ceon-eo baeyeol chogihwa null

원래는 저렇게 원소를 하나하나 초기화 해야하지만, 선언 당시에는 "~"이런 식으로 초기화가 가능합니다.

뒤에 널문자열이 원칙적으로는 있어야겠지만, 선언과 동시에 빈 곳들은 '\0'으로 초기화가 되기 때문에 앞 뒤 코드는

실질적으로는 차이가 없습니다.

C언어 배열 초기화 null - ceon-eo baeyeol chogihwa null

선언후 c = "QKRM"과 같이 초기화를 하려면 에러를 마주하게 됩니다.

이 에러를 해결하기 위해서는.

C언어 배열 초기화 null - ceon-eo baeyeol chogihwa null

다음과 같이 일일이 초기화를 해주거나, while문을 통해 하나하나 대입해주면 문자열을 선언한 뒤에

문자열을 대입할 수 있습니다. 하지만 이렇게 매번 복사한다는건 쉬운일이 아닙니다.

그래서 우리는 string.h 에 포함되어있는 strcpy 함수를 사용할 겁니다!

C언어 배열 초기화 null - ceon-eo baeyeol chogihwa null

이런식으로 strcpy함수를 통해서 b의 원소들을 c의 원소들로 복사해준다면 선언뒤 대입이 가능합니다!

strcpy는 위에 제가 while문으로 돌린것 처럼 원소를 하나하나 복사해서 대입해주는 함수입니다.

char *strcpy(char *dst, const char *src) {

배열이란 사용자가 의미상의 연관이 있는 동일한 자료형에 속한 여러 개의 자료들을 묶어 하나의 이름으로 정의한 자료형이다. 즉, 같은 이름과 같은 타입을 가진 연속적인 메모리 공간이라고 할 수 있다.

 

 

배열의 선언과 사용

배열은 일반적인 변수와 달리 값을 여러 개 저장할 수 있다. 1차원 배열을 선언하는 방법은 다음과 같다.

 

C언어 배열 초기화 null - ceon-eo baeyeol chogihwa null

 

자료형은 배열의 모든 원소가 가지는 공통적인 자료형으로 어떤 자료형도 올 수 있다. 배열이름은 사용자가 정의하는 배열의 이름이다. 배열길이는 배열이 가지는 요소의 개수를 나타내며 항상 양의 정수로 명시되고 대괄호 '[]'로 둘러싸인다. 배열길이를 선언할 때는 반드시 상수를 사용해야 한다.

int ages[10]

배열을 선언하면 변수의 개수만큼 연속된 메모리 공간을 할당한다.

 

C언어 배열 초기화 null - ceon-eo baeyeol chogihwa null

 

배열을 구성하는 기억공간들을 배열의 요소(element)라고 하며 각 요소가 배열에서 차지하는 위치를 첨자(index)라고 한다. 배열의 각 원소는 대괄호 '[]'의 인덱스로 나타낸다. 배열 요소의 위치는 1에서부터 시작하지 않고 0에서 부터 시작한다. 즉, 첫 번째 배열 요소의 인덱스는 0이다.

 

 

ages 배열의 세 번째 요소에 24라는 값을 입력하고 출력할때, ages 배열의 각 요소는 int형 변수로 사용될 수 있다.

C언어 배열 초기화 null - ceon-eo baeyeol chogihwa null

 

#include <stdio.h>
#pragma warning(disable:4996)

int main() {
	int idx;
	int score[10];
	long sum = 0;
	float average;

	for (idx = 0; idx != ( sizeof(score) / sizeof(score[0]) ); idx++) {
		printf("input score [%d]\n", idx + 1); // 사용자는 1번부터지만 백엔드에서 처리는 0번부터
		scanf("%d", &score[idx]);
	}

	for (idx = 0; idx != ( sizeof(score) / sizeof(score[0]) );idx++) {
		sum += score[idx];
		average = sum / 10;
	}

	printf("Average score : %.2f\n", average);
}
C언어 배열 초기화 null - ceon-eo baeyeol chogihwa null

 

int형 배열의 크기 한칸의 크기는 4바이트이므로 크기는 40이 된다. => sizeof(score) 의 값은 40이 된다.

따라서 sizeof(score) / sizeof(score[0]) = 40 / 4  가 되므로 10이 되어서 for문이 10번 돌아가게 될 것이다.

이러한 방법은 소프트 코딩방법으로, 하드코딩을 방지하기위해 반복문에 숫자보다는 변수화를 시켜주는 것이 프로그래머에게 좀 더 편리하게 유지보수가 가능하다.(하지만 C는 효율적인 언어이기때문에 계산의 용량을 처리하는것도 아끼기위해 숫자를 넣는다고한다)

 

 

배열의 초기화

배열은 선언시 초기화 할 수 있다. 배열의 초기화는 중괄호 '{ }'를 사용한다. 다음은 배열 초기화의 예시이다.

 

C언어 배열 초기화 null - ceon-eo baeyeol chogihwa null

 

배열 요소의 수보다 초기화 값이 적으면 남은 기억공간은 0으로 채워진다.

 

C언어 배열 초기화 null - ceon-eo baeyeol chogihwa null
string이든 int이든 상관없이 빈 공간은 0으로 채워진다

 

배열을 선언할 때 초기화하면 배열 요소의 개수를 생략할 수 있다. [ ] 안에 숫자를 넣지 않더라도 배열의 요소 개수에 따라서 자동으로 기억공간이 자동으로 할당된다.

 

C언어 배열 초기화 null - ceon-eo baeyeol chogihwa null

 

배열은 자동, 외부 또는 정적 클래스로 지정할 수 있으나 레지스터 클래스로 지정할 수는 없다. 

만약 [ ] 안의 숫자와 배열 요소의 개수가 다르면 컴파일러는 에러로 처리한다.

 

 

문자열

문자형 상수는 작은따옴표 ' '  를 이용하여 표시하고, 문자열 상수는 큰따옴표 " " 로 표시한다.

 

C언어 배열 초기화 null - ceon-eo baeyeol chogihwa null

 

문자열은 문자형 배열로, 문자열을 저장하는 하나의 변수와 같은 역할을 한다. 문자배열은 기본적으로 여러 개의 문자를 저장하기 위한 char형 배열이다. 배열 요소에 문자를 저장하면 문자열이 된다.

 

C언어 배열 초기화 null - ceon-eo baeyeol chogihwa null

 

문자배열의 마지막에 널문자가 없으면 저장된 문자열의 끝을 알 수 없다.

이 경우에 printf함수로 출력할 경우 쓰레기값이 출력된다.

 

C언어 배열 초기화 null - ceon-eo baeyeol chogihwa null

 

char 배열 출력을 디버그모드로 메모리에 어떻게 저장되는지 확인해보자.

#include <stdio.h>
int main() {
	char word[4];
	word[0] = 'L';
	word[1] = 'o';
	word[2] = 'v';
	word[3] = 'e';
	
	printf("%c\n", word[0]);
	printf("%c\n", word[1]);
	printf("%c\n", word[2]);
	printf("%c\n", word[3]);
    
	return 0;
}

 

C언어 배열 초기화 null - ceon-eo baeyeol chogihwa null

 

printf문을 4줄을 써서 출력했는데 for문으로도 출력할 수 있지만 문자열 출력할때 사용하는 %s로도 출력할 수 있다.

printf("%s\n", word); 를 작성하면 Love가 나오긴하는데, 뒤에 쓰레기값이 같이 출력된다.

 

C언어 배열 초기화 null - ceon-eo baeyeol chogihwa null

컴파일러가 printf("%s\n", word); 를 실행할때 word 배열 요소를 출력하게되는데, 컴파일러가 배열의 끝을 0으로 인식하고있기때문에 배열 요소를 벗어나서 쓰레기값이 출력되는 것이다.

한자나 한글은 2바이트이기 때문에 cc cc cc cc 99 57 8a a9 4글자가 출력되고, 그 다음 00을 만나므로 출력문이 종료되는 것이다.

 

여기서 사용한 char배열 word는 문자 배열이다. 문자열은 문자배열이지만 문자배열은 문자열이 아니다.(문자열이 좀 더 상위 집합이다.) C에서는 string 문자타입(char형)을 배열형태로 만들어서 저장하게되는데, 이것을 문자열로 정의한다.

 

참고로 C#에서는 char타입이 존재하지만, 문자열을 사용할때는 스트링이라는 클래스가 따로 존재한다.(string.Foramt, string.Substring 등이 들어있는 클래스)

 

Null이 있으면 문자열이 되고, Null이 없으면 문자배열이 된다. 문자열은 Null이 끝나는걸로 약속했기때문에 컴파일러는 0까지 찾는다. 그래서 이런 것을 방지하기위해 배열 공간을 정할때, 문자열크기에서 필요한 바이트만큼의 크기 + 1을 해서 사용하는것이 좋다.

#include <stdio.h>
#pragma warning(disable:4996)

int main() {
	char word[5];
	word[0] = 'L';
	word[1] = 'o';
	word[2] = 'v';
	word[3] = 'e';
	word[4] = 0;
	//word[4] = '\0';

	printf("[%c]\n", word[0]);
	printf("[%c]\n", word[1]);
	printf("[%c]\n", word[2]);
	printf("[%c]\n", word[3]);
	printf("[%c]\n", word[4]);

	printf("[%s]\n", word);
	return 0;
}
C언어 배열 초기화 null - ceon-eo baeyeol chogihwa null

 

Love에서 필요한 크기의 4 + 1을 할당해주고, 맨 마지막 요소에 0(Null)을 대입하면 쓰레기값이 출력되지않고 필요한 데이터값만 출력되는 것을 알 수 있다.(이때 '\0' (역슬래시 0)을 넣어줘도 된다)

 

참고로 출력문에 [ ]를 붙여서 출력하는 이유는 Null값을 넣었을때 확인하기 위해서 붙여주었다.

(만약 \t를 붙였으면 Tab 효과가있는데 이를 확인하기위해 붙여주는 경우가 많다고한다)

 

C에서 배열을 선언해서 초기화할때 방법이 여러가지 있다.

 

위에서 말한것처럼 word[0], word[1] ... 배열 요소 하나하나 선언해서 초기화 하는 방법도 있고,

char word[5] = {"Love"};  처럼 중괄호에 한꺼번에 초기화하는 방법도 있다.

#include <stdio.h>
#pragma warning(disable:4996)

int main() {
	char word[5] = { "Love" };

	printf("[%c]\n", word[0]);
	printf("[%c]\n", word[1]);
	printf("[%c]\n", word[2]);
	printf("[%c]\n", word[3]);

	printf("[%s]\n", word);
	return 0;
}
C언어 배열 초기화 null - ceon-eo baeyeol chogihwa null
출력결과는 같다

 

또다른 방법으로, 중괄호 { } 를 쓰지않고 C#처럼 큰 따옴표 " "만 사용하는 방법도 있다.

아마 이 방법이 제일 편한 방법이지 않을까 싶다. 

#include <stdio.h>
#pragma warning(disable:4996)

int main() {
	char word[5] = "Love";

	printf("[%c]\n", word[0]);
	printf("[%c]\n", word[1]);
	printf("[%c]\n", word[2]);
	printf("[%c]\n", word[3]);

	printf("[%s]\n", word);
	return 0;
}
C언어 배열 초기화 null - ceon-eo baeyeol chogihwa null
출력결과는 같다

 

 

 

 

C언어 배열 초기화 null - ceon-eo baeyeol chogihwa null

 

char str[10] = {'d', 'r', 'e', 'a', 'm', '\0', '\0', '\0', '\0', '\0'};로 초기화 했을때는

C언어 배열 초기화 null - ceon-eo baeyeol chogihwa null

char string[5] = {"sunny"}; 의 경우 컴파일러는 char string[5] = {'s','u','n','n','y',};로 초기화한다. 따라서 string은 문자열이 아니다.

배열은 문자열상수로 직접 초기화가 가능하다. 단, 선언과 동시에 초기화하는 경우만 가능하다.

 

C언어 배열 초기화 null - ceon-eo baeyeol chogihwa null

 

 

문자열 길이를 구하는 예제

// 문자열 길이 구하는 예제
#include <stdio.h>
#pragma warning(disable:4996)
int main() {
	char string[] = { "Happy Day" };
	int idx;

	for (idx = 0; string[idx] != '\0'; idx++) 
        {
		printf("%c", string[idx]);
	}
	printf("\nString length : %d\n", idx);
	return 0;
}
C언어 배열 초기화 null - ceon-eo baeyeol chogihwa null

 

 

 

문자열 로테이션 시키는 예제

// 문자열 로테이션 시키는 예제
#include <stdio.h>
#pragma warning(disable:4996)
int main() 
{
	int idx;
	char ch;
	char str[9] = { "Rotation" };

	printf(" -- 변경 전 문자열 -- \n");
	printf("%s\n", str);

	for (idx = 0; idx != 9; idx++)
		printf("%c ", str[idx]);

	printf("\n\n -- 변경 중 -- \n");
	for (idx = 0; idx != 4; idx++) 
	{
		ch = str[7 - idx];
		str[7 - idx] = str[idx];
		str[idx] = ch;

		printf("%s\n", str);
	}

	printf("\n -- 변경 후 문자열 -- \n");
	printf("%s\n", str);
	return 0;
}
C언어 배열 초기화 null - ceon-eo baeyeol chogihwa null


로테이션 예제는 Rotation 8글자에서 양끝에서부터 가운데로 2글자씩 위치를 바꿔준것이다.

for문이 돌아가는 idx에 숫자를 대입해보면 다음과 같다.

str[7]  str[0]  

str[6]  str[1]  

str[5]  str[2]  

str[4]  str[3]  

 

Rotation이 8글자인데 4쌍이므로 idx가 4번 도는것으로 for문을 작성하였다.(7은 Rotation의 길이이다)

 

이때 서로 대입만하면 원래값이 사라질 수 있으므로 임시로 변수 1개를 생성해서 한쪽에서 한쪽을 넣기 전에 char ch를 선언해서 ch에 넣고, 서로 값을 바꿀 수 있게 되는 것이다.