Notice
Recent Posts
Recent Comments
Link
«   2025/01   »
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 31
Tags
more
Archives
Today
Total
관리 메뉴

나의 IT일지

배열 본문

프로그래밍 언어/C언어

배열

세레프 2023. 2. 16. 06:19

 컴퓨터는 데이터의 값을 저장하기 위해선 메모리에 변수를 선언해서 변수에 값을 저장한다. 그런데 이러한 변수도 데이터를 1개만 저장을 할 수 있다. 하지만 우리는 많은 데이터값을 다루기 때문에, 많은 데이터를 한 번에 저장할 수 있는 방법이 필요하다. 

배열

 위의 문제점을 해결하기 위한 것이 배열이라는 존재이다. 배열이란 같은 자료형을 가진 여러 개의 변수를 이어놓은 형태를 가진 변수의 묶음으로, 같은 변수를 사용하여 많은 데이터를 처리할 때에 사용한다. 배열의 종류로는 1차원배열다차원배열이 있는 데, 여기에선 1차원 배열에 대해서 알아볼 것이다.

자료형 배열명[요소 개수];

 위의 구조는 배열의 선언 방법으로, 어떤 형태의 데이터를 저장할 것인지 선언하는  자료형배열의 이름배열명, 배열에 몇 개의 변수를 만들 것인지 선언하는 요소 개수로 구성되어 있다. 예시로 "int a[ i ]"의 요소들을 표현해 보자.

 배열의 각 요소들은 "배열명[호출번호]"로 표현되며, 호출할 때에는 호출변호를 통해 저장공간을 호출하면 된다. 이때 요소의 호출번호(index값)를 보면 마지막 호출번호가 "i-1"인것을 볼 수 있는데, 이는 첫번째 index값이 "0"부터 시작해서 나타나는 현상이다.

 

 배열도 변수처럼 초기화를 할 수 있다. 초기화란 선언한 후 바로 값을 대입하는 것으로, 여러개를 선언할 때에는 쉼표를 통해 배열의 초기값을 구분한다.

  1. 자료형 배열명[배열크기] = {초기값1, 초기값2...}
  2. 자료형 배열명[]= {초기값1, 초기값2...}

 1번 형식배열크기를 정하고 초기값을 선언하는 형식으로, 초기값의 갯수가 배열의 크기보다 작거나 같아야 한다. 만약 배열의 크기가 초기값의 갯수보다 클 경우, 남은 배열요소는 모두 0으로 채워진다.

 그리고 2번 형식에는 배열크기를 정하지 않은 상태에서 선언하는 것을 볼 수 있다. 이렇게 선언을 하면, 값의 갯수만큼 요소가 생성이 된다.

 

#include<stdio.h>

void array_copy(int arr_1[], int arr_2[]);
void main() {
	int a[5] = { 1,2,3,4,5 };
	int b[5];
	array_copy(a, b);

	printf("a:");
	for (int i = 0; i < 5; i++) {
		printf("%d ", a[i]);
	}
	printf("\n");
	printf("b:");
	for (int i = 0; i < 5; i++) {
		printf("%d ", b[i]);
	}
}

void array_copy(int arr_1[], int arr_2[]) {
	for (int i = 0; i < 5; i++) {
		arr_2[i] = arr_1[i];
	}
}

 위의 코드는 초기화한 배열 a의 값을 배열 b에 복사하는 코드로, "array_copy()"함수를 보면 반복문을 통해 배열 a의 요소들의 값을 배열 b의 요소에 저장하는 것을 볼 수 있다. 즉, 생성된 배열의 요소에 값을 저장할 때에는 요소마다 하나씩 값을 저장해줘야 한다. 달리 말하면,  배열을 생성된 상태에선 초기화에서 사용한 것처럼 한꺼번에 값을 요소에 저장할 수 없다

 

배열의 특징

 배열은 모든 요소가 같은 자료형을 가지며, 요소가 연속적으로 나열되어 있다. 

#include<stdio.h>

void main() {
	int a[3];
	printf("a=%d\n", &a);
	printf("a=%d\n", a);
    
	printf("a[0] = %d\n", &a[0]);
	printf("a[1] = %d\n", &a[1]);
	printf("a[2] = %d\n", &a[2]);
    
	printf("sizeof(a)=%d\n", sizeof(a));
	printf("sizeof(a[0])=%d\n", sizeof(a[0]));
	printf("sizeof(a[1])=%d\n", sizeof(a[1]));
	printf("sizeof(a[2])=%d\n", sizeof(a[2]));
}

 위의 결과를 보면 배열 a의 요소들의 저장공간이 4byte이며, a[0]를 시작으로 연속적인 순서로 주소를 가지고 있는 것을 확인할 수 있다. 이는 배열a의 요소들은 정수형의 요소이며, 연속적으로 나열되어 있다는 것을 알 수 있다. 즉 배열 a의 요소를 다음과 같이 표현 할 수 있다.

 위의 소스코드와 실행 결과에서 배열 a의 주소와 요소 a[0]의 주소, 배열 a의 이름의 출력값이 동일한 것을 확인할 수 있다.  배열 a의 주소와 요소 a[0]의 주소가 같은 것은 "배열 a의 첫 요소가 a[0]라는 것을 의미"하며, 배열 a의 이름을 정수형으로 출력했을 때, 배열 a의 주소와 같게 나타난 것은 "배열의 이름이 배열의 주소라는 것을 의미"하는 것이며, 배열 이름의 값은 주소값을 가진다는 것을 의미한다.

 

 


배열의 예시: 문자열

 문자열은 자료형이 문자형인 배열로, "hello world"와 같이 쌍따옴표로 표현될 여러 개의 문자들을 저장할 때 사용되는 배열이다. 

 

문자열 또한 배열이기에 초기화를 할 수 있으며, 초기화하는 방법은 다음과 같다.

  1. 문자형 자료형 배열명[]= "문자열 값"  
  2. 문자형 자료형 배열명[]= {'문자 1','문자 2','문자 3','문자 4'...}

 1번 형식은 쌍따옴표안에 있는 문자열 상수의 글자 수만큼 배열의 요소가 생성되어 저장되는 형식이며, 2번 형식은 중괄호 안에 있는 문자 상수의 수만큼 배열의 요소가 생성되어 저장되는 형식이다. 

 이렇게 보면 1번형식과 2번 형식은 차이가 없다고 생각할 수 있다. 하지만 이 두 형식에는 엄청난 차이가 존재한다.

#include<stdio.h>

void main() {
	char str1[] = "apple jam";
	char str2[] = { 'a','p','p','l','e',' ','j','a','m'};
	printf("문자열의 크기 비교\n");
	printf("sizeof(str1):%d\n", sizeof(str1));
	printf("sizeof(str2):%d\n", sizeof(str2));

	printf("문자열의 출력 비교\n");
	printf("str1:%s\n", str1);
	printf("str2:%s\n", str2);
}

  위의 코드를 보면, 문자열 str1은 1번 형식으로, 문자열 str2는 2번 형식으로 만들었다. 해당 코드를 출력하면 다음과 같은 현상이 발생한다.

  • 1번 형식의 문자열의 크기는 "문자열 상수의 글자수+1"이며, 2번 형식의 문자열의 크기는 "문자 상수의 갯수"이다.
  • 1번 형식의 문자열의 출력은 깔끔하지만, 2번 형식의 문자열의 출력은 쓰레기값이 같이 출력된다.

 이는 널 문자(\0)의 유무차이이다. 널 문자문자열의 끝을 표시해 주는 문자이다. 배열은 초기화가 끝나고 남는 요소들은 자동적으로 0이 채워지게 된다. 이때, 문자열 또한 자동적으로 0이 채워지게 되는데, 유독 문자열에서 널 문자라고 따로 구분이 되는 것은 printf함수가 char형 배열에서는 널 문자가 나올때까지 출력하도록 만들어 졌기 때문이다. 즉, 1번 형식은 마지막에 널 문자가 있어서 "apple jam"까지 출력이 된 것이지만, 2번 형식은 널 문자가 없기 때문에 뒤에 쓰레기값이 추가적으로 출력이 되는 것이다.

 

 scanf함수도 마찬가지이다. scanf함수도 문자열의 형식으로 작성하여 저장한다면, 자동적으로 마지막 요소에 널 문자가 추가되도록 만들어 졌다. 즉, 큰따옴표로 선언한 문자열에 문자 형식으로 "grape"를 작성하여 문자열을 변경한다면, 출력결과는"grape jam"이 되고, 문자열 형식으로 "grape"를 작성하여 문자열을 변경한다면, 출력결과도 "grape"로 출력이 된다. 

#include<stdio.h>

void main() {
	char str1[] = "apple jam";
    
    printf("str1: %s\n",str1);

	printf("문자 입력 비교\n");
	printf("grape 입력(문자형태)\n");
	scanf("%c %c %c %c %c", &str1[0], &str1[1], &str1[2], &str1[3], &str1[4]);
	printf("str1:%s\n", str1);

	printf("grape 입력(문자열 형태)\n");
	scanf("%s", str1);
	printf("str1:%s\n", str1);

}

 그래서 char형 배열을 선언 할 때에는 문자 형식이 아닌 문자열 형식을 사용하는 것이며, 배열 요소의 개수를 정할 때, "문자열 길이 + 1"개로 정한다. 

 

 

 

 문자열 전용 입출력 함수 : gets, puts

 키보드를 통해서 문자열을 입력해야 하는 경우에 주로 gets함수를 사용하게 된다. 이유는 scanf함수는 char형 문자형을 입력받을 때, 중간에 빈칸이 존재하면, 빈칸 전의 내용까지만 저장을 한다. 즉 "hello world"에서 "hello"만 저장하는 것이다. 이를 막기 위해서 사용되는 것이 gets함수이며, puts함수는 gets함수와 짝을 이루는 출력함수이다.

 

기타 입출력함수

컴파일러를 사용할 때, printf()와 scanf()를 통해 입출력을 할 수 있다. 그렇다면 다음 소스코드를 한번 보자. #include void main() { int grade; char point; printf("성적:"); scanf("%d", &grade); //int_a의 주소에 3자리

my-it-diary.tistory.com

 

 

 

번외2)  string 헤더파일

string헤더파일은 문자열과 관련된 함수를 모아놓은 헤더파일이다.

  • strcpy(문자열 1, 문자열 2) : 문자열 1 에 문자열 2 값 복사하는 함수로, 문자열은 "="연산자를 사용할 수 없기 때문에 사용한다. 사용할 때에는 sdl검사를 끄고 사용해야 함
  • strlen(문자열) : 문자열의 길이를 구하는 함수로, 널 문자를 제외한 문자의 개수를 출력한다. 사용할 때에는 sdl검사를 끄고 사용해야 함
  •  strcat(문자열 1,문자열 2) :  문자열 1 에 문자열 2 값 을 연결하는 함수로, 문자열 1의 널문자를 삭제하고 문자열 2의 내용을 연결한 뒤에 널문자 추가한다. 사용할 때에는 sdl검사를 끄고 사용해야 함
  • strcmp(문자열 1,문자열 2) : 문자열 1 에 문자열 2 값을 비교하는 함수
#include<stdio.h>
#include<string.h> 

void main() {
	char country[10] = "korea";
	char nation[10];
	strcpy(nation, country);
	
	printf("country:%s, nation:%s", country, nation);
}

위의 코드에 대한 출력결과

'프로그래밍 언어 > C언어' 카테고리의 다른 글

포인터의 기본  (0) 2023.02.18
다차원 배열  (0) 2023.02.17
함수와 변수  (0) 2023.02.15
함수  (0) 2023.02.14
다중 반복문  (0) 2023.02.13
Comments