문자를 저장하는 배열
메모리에 문자를 순서에 맞게 연속으로 저장하기 때문에 결국 순서를 다루는 배열은 주로 문자열을 저장하는 데 가장 많이 사용됩니다. 모든 알파벳 문자는 한 바이트로 충분히 사용될 수 있으니 char형 배열을 사용하는 것이 좋습니다.
char형 배열을 선언할 때 꼭 기억해야 할 점은 저장할 문자열의 길이보다 최소한 하나 이상 크게 배열을 선언해야 한다는 것입니다. 예를 들어 문자열 "apple"을 저장할 배열은 배열 요소 개수가 최소한 6개 이상이어야 합니다.
a | p | p | l | e |
이 여분의 공간이 필요한 이유는 널 문자(\0)를 저장하기 위해서입니다. 널 문자의 기능은 다음 예제를 통해 확인해보겠습니다.
#include <stdio.h>
int main(void)
{
char str[80] = "applejam"; //문자열 초기화
printf("최초 문자열 : %s\n", str); // 초기화 문자열 출력
printf("문자열 입력");
scanf("%s", &str); //새로운 문자열 출력
printf("입력 후 문자열 : %s\n", str); //입력된 문자열 출력
return 0;
}
//실행 결과
최초 문자열 : applejam
문자열 입력 : grape
입력 후 문자열 : grape
널 문자의 용도
초기화한 문자는 배열의 처음부터 차례로 저장되어 문자열을 만듭니다. 이때 남는 배열 요소에는 자동으로 0이 채워집니다. 이렇게 char형 배열에 저장된 0을 특별히 널 문자(null character)라고 부릅니다. 모든 문자는 아스키 값으로 저장되므로 결국 널 문자는 아스키 코드 값이 0인 문자를 말하며 문자 상수로는 \0으로 표현됩니다.
a | p | p | l | e | j | a | m | \0 | \0 | ... |
아스키 코드 값이 0인 문자를 널 문자라는 이름으로 지정한 이유는, 널 문자가 문자열의 끝을 표시하는 용도로 쓰이기 때문입니다. 첫 printf가 배열의 크기와 상관없이 초기화된 문자열만을 정확히 출력하는 것도 널 문자가 있기 때문입니다. printf함수는 char형 배열에서 널 문자가 나올 때까지만 출력하도록 만들어졌습니다. 이런 규칙은 문자열을 처리하는 모든 함수에 적용됩니다.
scanf 함수로 문자열을 입력받을 때도 널 문자가 사용됩니다. scanf 함수가 배열의 처음터 grape만 입력했다면, "입력 후 문자열 : " 다음 출력 결과는 grapejam 이어야 합니다. 그러나 scanf함수는 사용자가 입력한 문자열 다음에 자동으로 널 문자를 추가해 문자열의 끝을 표시합니다. 따라서 마지막의 printf함수는 grape 까지만 출력됩니다.
a | p | p | l | e | j | a | m | \0 | \0 |
g | r | a | p | e | \0 | 그 다음은 출력 안 됨 |
char형 배열을 선언할 때 주의할 점을 정리하고 넘어가겠습니다.
- 배열의 크기는 최대한 넉넉하게 선언해야 합니다. 나중에 다른 문자열을 저장하게 될 일이 생길지도 모르니까요.
- 배열 요소의 개수는 최소한 '문자열 길이 + 1'이어야 합니다. 널 문자를 저장할 공간을 지정해주어야 합니다.
문자열 대입
char형 배열이 문자열을 저장하는 변수의 역할을 하므로 초기화된 이후에도 얼마든지 새로운 문자열을 저장할 수 있습니다. 단, 문자열의 길이가 다를 수 있으므로 일반 변수처럼 대입 연산자를 사용하는 것은 불가능합니다. 이때는 strcpy함수를 사용합니다.
strcpy함수는 char형 배열에 새로운 문자열을 저장하는 함수로, 저장할 문자열의 길이를 파악해 딱 그 길이마나큼만 char형 배열에 문자열을 복사합니다. 물론 문자열 끝에 널 문자도 자동으로 붙여 줍니다. 예제를 통해 확인해보겠습니다.
#include <stdio.h>
#include <string.h>
int main(void)
{
char str1[80] = "cat";
char str2[80];
strcpy(str1, "tiger"); // str1배열에 문자열 "tiger" 대입
strcpy(str2, str1); // str2배열에 str1배열에 저장된 문자열을 복사
printf("%s, %s\n", str1, str2); //
return 0;
}
//실행결과
tiger, tiger
우리가 지금까지 못 보던 헤더 파일이 등장했습니다. sting.h는 문자열을 다루는 함수들의 원형을 모아 놓은 것으로, strcpy 함수에 접근하기 위해 사용됩니다. strcpy의 기본 사용법은 다음과 같습니다.
strcpy(저장될 배열명, 저장할 문자열)
문자열 전용 입출력 함수 : gets, puts
char형 배열에 문자열을 대입하는 일은 strcpy 함수가 훌륭히 수행합니다. 이제 키보드로 문자열을 입력하는 문제를 생각해 보겠습니다. scanf함수는 char형 배열에 문자열을 입력할 수 있으나 중간에 빈칸이 있는 경우 빈칸 전까지만 입력합니다. 따라서 빈칸을 포함해서 문자열을 입력할 수 있는 새로운 방식이 필요합니다.
gets 함수는 빈칸을 포함해 한 줄 전체를 문자열로 입력합니다. 또한 이 함수와 짝을 이루는 문자열 출력 함수 puts도 있습니다. 예제를 통해 puts와 gets함수의 사용법과 특징을 알아보겠습니다.
#include <stdio.h>
int main(void)
{
char str[80];
printf("문자열 입력 : "); //입력 안내메시지 출력
gets(str); //빈칸을 포함한 문자열 입력
puts("입력된 문자열 : "); //문자열 상수 출력
puts(str); //배열에 저장된 문자열 출력
return 0;
}
//실행결과
문자열 입력 : love is in your eyes
입력된 문자열 :
love is in your eyes
gets함수의 사용법은 간단합니다. 인수로 char형 배열의 배열명을 줍니다.
gets(char형 배열명)
gets함수는 문자열 입력 중간에 빈칸이나 탭 문자를 활용할 수 있으며, enter를 누르기 전까지 전체를 하나의 문자열로 배열에 저장합니다. 물론 마지막에 널 문자를 붙여서 문자열의 끝을 표기합니다.
puts 함수는 문자열 상수나 char형 배열의 배열명을 주면 문자열을 화면에 출력합니다. printf와 기능이 같지만 문자열을 출력한 후에 자동으로 줄을 바꿔준다는 차이점이 있습니다. 경우에 따라 더 편할 수도 있지만, 문자열을 출력한 후에 바로 이어서 입력하는 것은 불가능합니다.
printf("문자열 입력 : ") // 입력 안내 메시지를 출력하고 줄이 바뀌지 않음
gets(str); // 출력한 문자열 바로 앞에서 입력. 입력 후 자동으로 줄바꿈
문자열 처리에서 핵심 포인트를 정리해보겠습니다.
구분 | 사용 예 | 기능 |
char형 배열 초기화 | char str[80] = "apple"; | char형 배열은 문자열로 초기화한다. 문자열의 끝에는 널 문자가 있다. |
문자열 대입 | char str[80]; strcpy(str, "apple"); |
문자열 대입은 대입 연산자 대신 strcpy함수를 사용한다. str배열에 문자열 "apple"저장 |
문자열 입출력 | char str[80]; scanf("%s",str); gets(str); printf("%s", str); puts(str); |
scanf 함수는 하나의 단어만 입력 gets 함수는 한 줄 입력 printf 함수는 문자열 출력 puts 함수는 문자열 출력 후 줄 바꿈 |
확인 문제
다음 중 char형 배열이 바르게 초기화된 것을 고르세요.
- char str[80] = {'p', 'i', 'g'};
- char str[ ] = "elephant";
- char str[5] = "apple";
- char str[2] = {"sun", "moon"};
1 - O. 남는 배열 요소에는 자동으로 0이 채워집니다
2 - O. 문자열 끝의 널 문자를 포함해 9개의 배열 요소를 할당합니다.
3 - X. 널 문자를 저장할 공간이 없습니다.
4 - X. 배열의 크기가 작고, 중괄호 없이 하나의 문자열만 초기화할 수 있습니다.
2개의 문자열을 입력받아 위치를 바꾼 후 출력하는 프로그램을 작성하세요.
5개의 정수 중 최댓값과 최솟값의 위치를 출력하는 프로그램을 작성하세요.
#include <stdio.h>
#define NUMBER 5
int main(void)
{
int i, max, min, index1, index2;
int ary1[NUMBER]; //arry[0] ~ arry[4]
int ary2[NUMBER]; //arry[0] ~ arry[4]
int ary[NUMBER]; //arry[0] ~ arry[4]
max = 0;
min = ary[0];
for (i = 0; i < NUMBER; i++)
{
scanf("%d", &ary[i]);
ary1[i] = ary[i];
ary2[i] = ary[i];
if(max <= ary1[i])
{
max = ary1[i]; // max에다가 최댓값 저장
index1 = i + 1; // 위치
}
if(min >= ary2[i])
{
min = ary2[i]; // min 에다가 최솟값 저장
index2 = i + 1; // 위치
}
}
printf("가장 큰 값은 %d입니다.%d번째에 있습니다.\n", max, index1);
printf("가장 작은 값은 %d입니다.%d번째에 있습니다.", min, index2);
return 0;
}
3
6
8
4
6
가장 큰 값은 8입니다. 그리고 3번째에 있습니다.
가장 작은 값은 3입니다. 그리고 1번째에 있습니다.
5개의 정수 중 짝수인 최댓값과 홀수인 최솟값의 위치를 출력하는 프로그램을 작성하세요.
#include <stdio.h>
#define NUMBER 5
int main(void)
{
int i, max, min, index1, index2;
int ary1[NUMBER]; //arry[0] ~ arry[4]
int ary2[NUMBER]; //arry[0] ~ arry[4]
int ary[NUMBER]; //arry[0] ~ arry[4]
max = 0;
for (i = 0; i < NUMBER; i++)
{
scanf("%d", &ary[i]);
ary1[i] = ary[i];
ary2[i] = ary[i];
if(max <= ary1[i] && (int)ary1[i] % 2 == 0)
{
max = ary1[i]; // max에다가 최댓값 저장
index1 = i + 1; // 위치
}
if((int)ary2[i] % 2 == 1) //홀수일 경우를 먼저
{
if(min >= ary2[i])
{
min = ary2[i]; // min 에다가 최솟값 저장
index2 = i + 1; // 위치
}
}
}
printf("가장 큰 값은 %d입니다.%d번째에 있습니다.\n", max, index1);
printf("가장 작은 값은 %d입니다.%d번째에 있습니다.", min, index2);
return 0;
}
//실행결과
2
3
4
55
44
가장 큰 값은 44입니다.5번째에 있습니다.
가장 작은 값은 3입니다.2번째에 있습니다.
'Development > C' 카테고리의 다른 글
(C언어 기초) 14. 포인터의 이해 (0) | 2023.11.05 |
---|---|
(C언어 기초) 14. 포인터 (0) | 2023.11.05 |
(C언어 기초) 12. 배열 (0) | 2023.09.03 |
(C언어 기초) 11. 여러 가지 함수 유형 (0) | 2023.09.01 |
(C언어 기초) 10. 함수의 작성과 사용 (0) | 2023.09.01 |
댓글