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와 유사한 효과)
-
주의점
- 배열의 크기 정보는 함께 전달되지 않으므로,
- 배열의 크기(길이)를 별도의 매개변수로 함께 넘겨주어야 한다.
-
함수의 매개변수로 배열을 전달하고 그 함수에서 배열의 내용을 수정하면, 원래의 배열이 수정된다.
-
배열의 이름이 배열 첫 element의 주소이므로, 함수로 시작 element의 주소가 전달되기 때문이다.
Transclude of 13_변수의-영역과-데이터-공유#2-call-by-address-주소에-의한-호출
-
또한 배열을 함수로 전달하려면, 반드시 크기도 함께 알려주어야 한다.
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”);
}