1. 배열

구분배열구조체
형태동일 형태 반복상이한 형태 묶음
연속숫자 연속
문자열 연속
객체
예: 학생{학번int, 이름str}
  • 배열 (Array)

    • 같은 자료형의 변수를 연속적인 메모리에 저장하는 자료구조
    • <index, element> 쌍의 집합으로 구성된다.
    • index를 주면 해당하는 값이 대응되는 구조이다.
    • 배열은 주로 반복문으로 처리한다.
  • cf. datatype size

    Transclude of 03_변수와-데이터-입력#^datatype

1.1. 배열의 선언`

  • 배열 또한 다른 자료형처럼 선언을 통해서 저장 공간을 확보한다.

  • 많은 변수를 한 번에 선언하는 효과를 볼 수 있다.

  • 자료형 배열이름[크기];로 선언한다.

// 1차원 배열 선언
int a[5]; // {a[0], a[1], a[2], a[3], a[4]}
  • 인덱스는 0부터 시작한다.
// {a[0], a[1], a[2], a[3], a[4]}
  • 배열의 이름(a)은 첫 번째 요소(a[0])의 메모리 주소(base address)를 가리킨다.

1.2. 배열의 초기화

  • 배열도 변수와 마찬가지로 최초 할당된 저장 공간에는 쓰레깃값이 저장되어 있다.

  • 그래서 배열도 원하는 값을 가지려면 선언과 동시에 초기화를 해야 한다.

  • 배열은 중괄호({})로 묶어서 초기화한다.

  • 선언과 동시에 초기화할 수 있다.

int a[5] = {1, 2, 3, 4, 5};	// {1, 2, 3, 4, 5}
  • 값을 적게 넣으면 나머지는 0으로 채워진다.
int a[5] = {1, 2, 3};		// {1, 2, 3, 0, 0}
int a[5] = {0};				// {0, 0, 0, 0, 0}
  • 배열의 크기를 생략할 수 있다.
int a[] = {1, 2, 3, 4, 5};	// {1, 2, 3, 4, 5}

1.3. 배열의 사용

  • 배열의 사용: 배열의 이름(a)은 첫 번째 element(a[0])의 주소를 갖는다.

    • 주소: ary+0, &ary[0]
    • 이름: ary[0], *&ary[0], *(ary+0)
      • a[i]는 주소 a+i*sizeof(int)에 있는 값을 가져온다.
  • 주소는 base + 인덱스 * sizeof(자료형)와 같이 계산될 수 있다.

1.4. sizeof 연산자

  • sizeof() 연산자를 활용한 배열 처리
    • sizeof() 연산자를 통해 배열 전체 크기와 요소의 크기를 확인할 수 있다.

    • 배열 요소의 개수가 바뀌면 배열을 처리하는 반복문을 모두 수정해야 하는 부담이 있다.

    • 배열 전체의 크기를 구할 때 sizeof 연산자를 사용한다.

    • sizeof(배열명)은 배열 전체의 크기를 구하고, sizeof(포인터)는 포인터 하나의 크기를 구한다.

// 8-3. sizeof 연산자를 사용한 배열
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
 
int main(void) {
	int score[5];
	int i;
	int total = 0;
	double avg;
	int count; // 배열 요소의 개수를 저장할 변수
	count = sizeof(score) / sizeof(score[0]); // 배열 요소의 개수 계산
	
	for (i = 0; i < count; i++)		// 11행에서 계산한 count만큼 반복
		scanf("%d", &score[i]);
	
	for (i = 0; i < count; i++)		// 11행에서 계산한 count만큼 반복
		total += score[i];
	
	avg = total / (double)count;	// 총합을 count로 나누어 평균 계산
	
	for (i = 0; i < count; i++)		// 11행에서 계산한 count만큼 반복
		printf("%5d", score[i]);
	printf("\n");
	
	printf("평균 : %.1lf\n", avg);
	return 0;
}

2. 문자열

  • 문자열 (String)

    • 문자(char)의 배열로 표현된다.

    • 문자열의 마지막에는 항상 문자열의 끝을 나타내는 널 문자를 포함한다.

    • 예: “Hello”를 저장하려면 최소 6칸의 배열(H e l l o \0)이 필요하다.

  • 널 문자 (Null Character; \0)

    • 문자열의 끝을 표시한다.
    • 따라서 배열 요소의 개수는 최소한 ‘문자열 길이 + 1’이어야 한다.

2.1. 문자열의 선언과 초기화

// 8-4. 문자열을 저장하는 char형 배열 [변형: 모두 출력]
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
 
int main(void) {
	char str[80] = "applejam";			// 문자열 초기화
	// {'a', 'p', 'p', 'l', 'e', 'j', 'a', 'm', '\0', '\0', … }
	printf("최초 문자열: %s\n", str);	// 초기화 문자열 출력
	
	scanf("%s", str);	// 새로운 문자열 입력
	printf("%s", str);	// 입력된 문자열 출력
	
	int i; for (i = 0; i < 10; i++)
		printf("%s", str + i); // 입력된 문자열 출력
	return 0;
}
// 8-4. 문자열을 저장하는 char형 배열 [변형: 배열 활용]
#include <stdio.h>
 
int main(void) {
	char str[80] = "applejam";			// 문자열 초기화
	printf("최초 문자열: %s\n", str);	// 초기화 문자열 출력
	
	// 12ffd48 12ffd48 12ffd48
	printf("%x %x %x\n", str, str + 0, &str[0]);
	// 80 4 1
	printf("%d %d %d\n", sizeof(str), sizeof(str + 0), sizeof(str[0]));
	return 0;
}

2.2. 문자열 대입

  • 문자열 대입/복사 (strcpy() 함수)
    • 문자열의 길이가 다를 수 있으므로 일반 변수처럼 대입 연산자를 사용하는 것은 불가능하다.
    • strcpy 함수는 char형 배열에 새로운 문자열을 저장하는 함수로, 저장한 문자열의 길이를 파악하여 딱 그 길이만큼만 char형 배열에 복사한다.
    • string.h 헤더파일의 사용이 필요하다.
// 8-5. 문자열을 대입하는 strcpy 함수
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h> // 문자열 관련 함수 원형을 모아놓은 헤더 파일
 
int main(void) {
	char str1[80] = "cat";
	char str2[80];
	// cat, (null)
	
	strcpy(str1, &"tiger"); // str1 배열에 "tiger" 복사
	// tiger, (null)
	
	strcpy(str2, str1); // str2 배열에 str1 배열의 문자열 복사
	// tiger, tiger
	
	printf("%s, %s\n", str1, str2);
	return 0;
}
  • strcpy(dest, &origin)
    • origin에 있는 문자열 전체를 dest로 복사하는 함수
  • strncpy(dest, &origin, sizeof(origin))
    • origin에 있는 문자열을 dest로, n만큼만 복사하는 함수

2.3. 문자열 길이 계산

  • strlen()

2.4. 문자열 입출력

  • 문자열 전용 입출력 함수
    • gets 함수: 빈칸을 포함하여 한 줄 전체를 문자열로 입력한다.
    • puts 함수: 문자열 상수나 char형 배열의 배열명을 주면, 문자열을 화면에 출력한다.
    • cf. 화이트 스페이스: SPACE, \t, \n, \v, \f, \r
#include <stdio.h>
 
int main(void) {
	char str[80];
	
	printf("문자열 입력 : ");	// 입력 안내 메시지 출력
	gets(str);					// 빈칸을 포함한 문자열 입력
	
	puts("입력된 문자열 : ");	// 문자열 상수 출력
	puts(str);					// 배열에 저장된 문자열 출력
	return 0;
}

3. 다차원 배열

3.1. 2차원 배열

  • 2차원 배열

    • 배열의 요소로 1차원 배열을 갖는 배열이다.

    • 행(Row)과 열(Col)로 구성된 격자 형태의 데이터로 볼 수 있다.

    • 논리적으로는 격자 형태이나, 물리적 메모리에는 1차원(선형)으로 순서대로 저장된다.

  • 2차원 배열의 초기화

    • 일부 초깃값, 행의 수를 생략하거나, 1차원 배열의 초기화 방식으로 초기화할 수 있다.
int A[2][3]; = {{1, 2, 3}, {4, 5, 6}};
int A[2][3]; = {1, 2, 3, 4, 5, 6};
 
for (i = 0; i < row; i++) { // 입력
	for (j = 0; j < column; j++)
		scanf(“%d”, &score[i][j]);
}

(1) 2차원 char 배열

  • 2차원 char 배열
    • 여러 개의 문자열을 저장하는 배열
char animal[5][20];
count = sizeof(animal) / sizeof(animal[0]);
for (i = 0; i < count; i++) // 입력
	scanf(“%s”, animal[i]);
  • 2차원 char 배열의 초기화
char animal[][10] = { “dog”, “tiger” };

3.2. 3차원 배열

  • 3차원 배열
    • 3차원 배열은 2차원 배열을 요소로 가지며, 3개의 첨자를 사용하여 선언한다.
int score[2][3][4] = { // [면][행][열]
	{ { 11, 12 }, {13, 14} },
	{ { 21, 22 }, {23, 24} }
};

4. 함수의 매개변수로 배열 전달

  • 전달 방식

    • 배열을 함수의 매개변수로 넘길 때, 배열의 이름(주소값)이 전달
    • (Call-by-Reference와 유사한 효과)
  • 주의점

    • 배열의 크기 정보는 함께 전달되지 않으므로,
    • 배열의 크기(길이)를 별도의 매개변수로 함께 넘겨주어야 한다.

5. 포인터 배열

5.1. 포인터 배열

  • 포인터 배열

    • 처리할 데이터의 주소만 따로 모아놓아, 반복문을 통해 데이터를 효율적으로 처리할 수 있다.
  • char 포인터 배열

    • 여러 개의 문자열을 다루기에 편하다.
    • 포인터 배열의 초기화와 2차원 char 배열의 초기화 방법이 같다.
char *pary[2] = { “dog”, “elephant”};
for (i = 0; i < 2; i++) // 출력
	printf(“%s\n”, pary[i]);

5.2. 2차원 배열처럼 활용하는 포인터 배열

  • 1차원 배열을 포인터 배열로 연결하면 2차원 배열처럼 쓸 수 있다.
int ary1[2] = {1, 2, 3};  
int ary2[2] = {4, 5, 6};  
int *pary[2] = { ary1, ary2 };
 
for (i = 0; i < 2; i++) {	// 2행
	for (j = 0; j < 3; j++)	// 3열
		printf(“%5d”, pary[i][j]);
	printf(“\n”);
}