OneDev
[C] 20.문자열(String) 본문
▣ 목차
1. 문자열(String)
2. 널(Null)
3. 버퍼와 입력스트림(stdin)
4. 문자열 입력받기
5. 버퍼 비우기
6. 문자열 리터럴(literal)
7. 문자열 복사, 비교, 합치기 ( string.h 사용 X )
8. 문자열 길이 구하기 ( strlen() )
◎ 1. 문자열(String)
"문자열(string)" 이란 → 문자(char)들의 배열
문자열을 정의하는 방법은 크게 2 가지 이다.
(1) 배열과 널 문자( '\0 ') 이용
- 각 문자를 작은 따옴표로 감싸 배열에 저장
- 배열의 마지막에 널('\0') 을 넣어주어야 한다.
- 배열의 크기를 지정할 때 널 문자도 포함시켜 생각해야 한다 ( "hi" 라는 문자열을 저장하고자 한다면 크기를 2가 아닌 3으로 해야한다)
(2) 큰따옴표(" ") 이용
- 문자들을 나열한 것을 큰 따옴표로 묶어주면 알아서 각각의 문자 배열로 인식한다
- 이 경우에도 널 문자를 위한 공간 하나를 더 추가해줘야 한다
※ 배열의 정확한 크기를 알아야 하는 상황이 아니라면, [ ] 안을 빈칸으로 두어도 상관없다 (컴파일러가 알아서 원소의 수를 세어주기 때문).
※ 배열을 할당하지 않고 큰따옴표만을 이용해 문자열을 지정할 수 있다.
char word_1[] = {'h', 'e', 'l', 'l', 'o', '\0'};
char word_2[] = "hi";
char *str = "abcde" ; // 단, 이 경우에는 "리터럴" 이라 해서 수정이 불가능하다
" " (큰 따옴표) | ' ' (작은 따옴표) |
문자열(한 개 이상의 문자) 를 지정할 때 사용 | 한 개의 문자를 지정할 떄 사용 |
(예) "abcd", "hello", "world" | (예) 'g', 'o', 'o', 'd,' / 잘못된 표현 : 'abc', 'hi' |
◎ 2. 널(Null) 문자 (Null Character)
널(Null) - '\0' 로 나타내며, 문자 0과는 다르다.
널('\0') 은 아스키 값이 0 이고, 문자 0 은 아스키 값이 48이다.
널은 문자열에서 문자열의 끝이 어디인지 나타내주는 종료 문자의 역할을 한다.
◎ 3. 버퍼(buffer) 와 입력 스트림(stdin)
버퍼란 데이터를 주고 받을 때 임시로 데이터를 저장하는 공간을 말한다.
또한 여러 버퍼중에서 키보드의 입력을 처리하는 버퍼를 입력 스트림( stdin, 혹은 입력버퍼) 라고 부른다.
즉 키보드를 통해 입력되는 모든 정보는 일시적으로 stdin에 저장되었다가 나중에 입력에 종료되면 한꺼번에 처리되게 된다.
◎ 4. 문자열 입력받기
▶ scanf 를 이용한 문자열 입력받기
- scanf 함수를 이용해 문자열을 입력받을 경우 %s 형식으로 입력 받는다.
- 문자열의 이름은 배열을 가리키고 있는 포인터이기 때문에 &를 붙이지 않아도 배열의 시작 주소값을 잘 전달할 수 있다.
- scanf 함수는 ' '(공백), '\n'(Enter) , '\t'(Tab) 를 만날 때 까지 stdin 으로부터 데이터를 얻어온다 (만나면 입력을 종료한다)
- scanf 함수는 stdin 으로부터 의미가 있는 문자가 나올 때 까지 모든 공백 문자들을 무시한다. (여기서 의미 있는 문자란 공백문자인 ' ' , '\n', '\t' 를 제외한 문자들을 말한다)
#include <stdio.h>
int main(){
char words[30];
scanf("%s", words);
return 0;
}
%c 를 통해 하나의 문자(char)를 입력받을 수 있지만, scanf 함수를 이용할 때 %c 를 이용하는 것은 권장하지 않는다.
(%c 는 이유를 불문하고 stdin 에서 딱 한 개의 문자만을 가져오게 되는데, 이때 버퍼에 무엇이 남아있는지 잘 고려해줘야 한다)
※ 한 개의 문자를 입력받고 싶을 때에도 %s 를 이용해 문자열로 입력받도록 하자
(되도록이면 %c 는 사용하지 말자)
◎ 5. 버퍼 비우기
(1) fflush() 이용
-> Visual Studio 2015 부터는 표준을 따라 버퍼를 비우는데 작동되지 않는다
(2) getchar() 이용
getchar 함수는 stdin 에서 한 개의 문자를 읽어와 그 값을 리턴하는 함수이다. 이 때 한 문자를 읽어오면 그 문자는 stdin에서 사라지기 때문에 버퍼를 비우는데 활용할 수 있다,
◎ 6. 문자열 리터럴(literal)
▶ 리터럴(literal)
프로그래밍 언어에서 리터럴 이란 소스 코드 상에서 고정된 값을 가지는 것을 말한다.
특히 C 의 경우 큰 따옴표로 묶인 것들을 문자열 리터럴 (string literal) 이라 부른다.
char *pstr = "goodbye";
printf("hello");
scanf("%c", str[0]);
/* 위의 예시에서 goodbye, hello, %c 모두 리터릴이다 */
컴퓨터는 이러한 리터를들을 따로 모아서 보관한다.
메모리 영역중 텍스트 세그먼트(text segment)에 프로그램 코드와 상수, 리터럴 등이 여기서 정의 된다.
텍스트 세그먼트에 있는 내용들은 읽기만 가능하다.
(사실 컴파일러, 운영체제 등의 환경에 따라 다를 수 있다)
리터럴은 읽기만 가능하기 때문에 리터럴의 값을 변경하려고 하면 오류가 나게 된다.
반면 printf 처럼 읽기 작업만 수행하는 경우에는 잘 실행된다.
※ 위에서 큰 따옴표로 묶인 것들을 문자열 리터럴이라 부른다고 했지만, 아래의 경우 리터럴이라 부르기 애매하다.
char str[] = "hello" ;
왜냐면 위 배열의 정의는 사실 컴파일러에 의해 아래와 같이 해석되기 때문인데 ,
char str[] = {'h', 'e', 'l', 'l', 'o', '\0'} ;
이는 단지 str 이라는 배열에 hello 라는 문자열을 복사한 것일 뿐이기 때문이다.
그리고 위 배열은 텍스트 세그먼트가 아닌 스택(stack) 이라는 메모리 수정이 가능한 영역에 정의되고, 따라서 수정 또한 가능하다.
※ VS2017 이상에서는 리터럴을 char * 로 가리킬 수 없으며, 반드시 const char * 로 가리켜야 한다.
(덕분에 리터럴을 수정하는 것을 컴파일 선에서 막을 수 있다)\
◎ 7. 문자열 비교, 복사, 합치기
<string.h> 헤더에서 문자열을 편하게 다룰 수 있게 해주는 함수들을 제공해주지만, 여기서는 직접 구현해본 예시코드를 소개하겠다.
(1) 문자열 비교 함수
int compare(char *str1, char *str2) {
while (*str1) {
if (*str1 != *str2) {
return 0;
}
str1++;
str2++;
}
if (*str2 == '\0') return 1;
return 0;
}
(2) 문자열 복사 함수
int copy_str(char *dest, char *src) {
while (*src) {
*dest = *src;
src++; // 그 다음 문자를 가리킨다.
dest++;
}
*dest = '\0';
return 1;
}
(3) 문자열 합치기 함수
int str_add(char *dest, char *src) {
/* dest 의 끝 부분을 찾는다.*/
while (*dest) {
dest++;
}
/*
while 문을 지나고 나면 dest 는 dest 문자열의 NULL 문자를 가리키고 있게 된다.
이제 src 의 문자열들을 dest 의 NULL 문자 있는 곳 부터 복사해넣는다.
*/
while (*src) {
*dest = *src;
src++;
dest++;
}
/* 마지막으로 dest 에 NULL 추가 (왜냐하면 src 에서 NULL 이 추가 되지
* 않았으므로) */
*dest = '\0';
return 1;
}
◎ 8. 문자열 길이 구하기
(1) 직접 구현 → for 문, 혹은 while 문을 이용해 직접 구현 ( 쉬우니 넘어가겠다)
(2) strlen() 함수 이용
→<string.h> 헤더 파일에서 strlen() 함수가 제공된다. 이 함수를 사용하면 해당 문자열의 길이를 구할 수 있다
#include <stdio.h>
#include <string.h>
int main() {
char *str1 = "abcde";
printf("%d \n", strlen(str1));
return 0;
}
'Language > C' 카테고리의 다른 글
[C] 22. 전처리기 (preprocessor) (#include, #define, #error, #ifdef) (0) | 2023.07.26 |
---|---|
[C] 21. 구조체(struct) (0) | 2023.07.21 |
[C] 19.함수(function) (0) | 2022.08.23 |
[C] puts : 문자열 출력 함수 (0) | 2022.08.02 |
[C] 18. 포인터(pointer) (0) | 2022.07.27 |