-
[C] 문자열와 명령행 인자②C 2023. 5. 16. 09:16
02 문자열 관련 함수
문자배열 라이브러리와 문자열 비교
다양한 문자열 라이브러리 함수
- 문자열 비교와 복사, 그리고 문자열 연결 등과 같은 다양한 문자열 처리는 헤더파일 string.h에 함수원형으로 선언된 라이브러리 함수로 제공
- 함수에서 사용되는 자료형 : 64bit 원도우 시스템인 경우
- size_t : 비부호 정수 long long형(unsigned __int64)
- void * : 아직 정해지지 않은 다양한 포인터를 의미
함수원형 설명 void *memchr(const void *str, int c, size_t n) 메모리 str에서 n 바이트까지 문자 c를 찾아 그 위치를 반환 int memcmp(const void *str1, const void *str2, size_t n) 메모리 str1과 str2를 첫 n 바이트를 비교 검색하여 같으면 0, 다르면 음수 또는 양수 반환 void *memcpy(void *dest, const void *src, size_t n) 포인터 src 위치에서 dest에 n 바이트를 복사한 후 dest 위치 반환 void *memmove(void *dest, const void *src, size_t n) 포인터 src 위치에서 dest에 n 바이트를 복사한 후 dest 위치 반환 void *memset(void *str, int c, size_t n) 포인터 str 위치에서부터 n 바이트까지 문자 c를 지정한 후 str 위치 반환 size_t strlen(const char *str) 포인터 str 위치에서부터 널 문자를 제외한 문자열의 길이 반환 함수 strcmp()와 strncmp()
- 문자열 관련 함수는 대부분 str○○○()로 명명
- 대표적인 문자열 처리 함수인 strcmp()와 strncmp()는 두 문자열을 비교하는 함수이다.
- 헤더파일 string.h 삽입
int strcmp(const char * s1, const char * s1); 두 인자인 문자열에서 같은 위치의 문자를 앞에서부터 다를 때까지 비교하여 같으면 0을 반환하고, 앞이 크면 양수를, 뒤가 크면 음수를 반환한다. int strncmp(const char * s1, const char * s1, size_t maxn); 두 인자 문자열을 같은 위치의 문자를 앞에서부터 다를 때까지 비교하나 최대 n 까지만 비교하여 같으면 0을 반환하고, 앞이 크면 양수를, 뒤가 크면 음수를 반환한다. 함수 strcmp()는 인자인 두 문자열을 사전(lexicographically) 상의 순서로 비교하는 함수이다.
strncmp()는 두 문자를 비교할 문자의 최대 수를 지정하는 함수이다.
- 비교 방법은 인자인 두 문자열을 구성하는 각 문자를 처음부터 비교해 나간다.
- 비교 기준은 아스키 코드값이다. 두 문자가 같다면 계속 다음 문자를 비교하여 문자가 다를 때 까지 계속 비교한다.
- 결국 문자가 다른 경우 앞 문자가 작으면 음수, 뒤 문자가 작으면 양수, 같으면 0을 반환한다.
- 대문자가 소문자보다 아스키 코드값이 strcmp("java", "javA")는 양수를 반환한다.
- 마지막인 문자 '\0'은 아스키 코드값이 0이므로 다른 어느 문자보다 작다.
- strcmp("ab", "a")는 마지막에 문자 b와 '\0'를 비교하므로 양수를 반환한다.
strcmp("a", "ab") : 음수 strcmp("ab", "a") : 양수 strcmp("ab", "ab") : 0 strcmp("java", "javA") : 양수 # 문자 a가 A보다 크므로 양수 반환 strncmp("java", "javA", 3) : 0 # 인자 3인 문자 셋까지 비교하여 같으므로 0
입력한 단어들을 사전순으로 정렬
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> int main(void) { char words[100][21] = {'\0'}; int count = 0; char temp[21] = { '\0' }; while (1) { scanf("%s", &words[count][0]); if (strcmp(words[count], "quit") == 0) break; count++; } for (int i = 0; i < count; i++) { for (int j = 0; j < count; j++) { if (strcmp(words[i], words[j]) < 0) { strcpy(temp, words[i]); strcpy(words[i], words[j]); strcpy(words[j], temp); } } } for (int i = 0; i < count; i++) printf("%s\n", words[i]); /* input : ABC DEF CAT MOON QUEEN BEER aabc quit */ return 0; }
ABC BEER CAT DEF MOON QUEEN aabc
문자열 복사와 연결
함수 strcpy()와 strncpy
- 함수 strcpy()와 strncpy는 문자열을 복사하는 함수이다.
- 함수 strcpy()는 앞 인자 문자열 dest에 뒤 인자 문자열 source를 복사한다.
- 앞 인자가 완전히 뒤 인자로 바뀌게 되므로 첫 번째 인자인 dest는 복사 결과가 저장될 수 있도록 충분한 공간을 확보해야 한다.
- 함수 strncpy()는 복사되는 최대 문자 수를 마지막 인자 maxn으로 지정하는 함수이다.
char * strcpy(char * dest, const char *source); 앞 문자열 dest에 처음에 뒤 문자열 null 문자를 포함한 source를 복사하여 그 복사된 문자열을 반환한다.
앞 문자열은 수정되지만 뒤 문자열은 수정될 수 없다.char * strncpy(char * dest, const char * source, size_t maxn); 앞 문자열 dest에 처음에 뒤 문자열 source에서 n개 문자를 복사하여 그 복사된 문자열을 반환한다.
만일 지정된 maxn이 source의 길이보다 길면 나머지는 모두 널 문자가 복사된다.
앞 문자열은 수정되지만 뒤 문자열은 수정될 수 없다.errno_t strcpy_s(char * dest, size_t sizedest, const char *source);
errno_t strncpy_s(char * dest, size_t sizedest, const char * source, size_t maxn);두 번째 인자인 sizedest는 정수형으로 dest의 크기를 입력한다.
반환형 errno_t는 정수형이며 반환값은 오류번호로 성공하면 0을 반환한다.
Visual C++에서는 앞으로 함수 strcpy_s()와 strncpy_s()의 사용을 권장한다.- 항상 문자열은 마지막 NULL 문자까지 포함하므로 다음 부분 소스에서 문자배열 d에는 NULL 문자까지 복사된다.
char d[] = "C C++"; char s[] = "Java"; strcpy(d, s); # 결과는 d에도 "Java"가 저장된다.
char dest[80] = "Java"; char source[80] = "C is a language."; printf("%s\n", strcpy(dest, source)); # 함수호출 strcpy(dest, source)의 결과는 문자열 source 모두를 dest에 복사한 후, # 반환값은 문자 포인터 dest 임 printf("%d\n", strcpy_s(dest, 80, source)); printf("%s\n", dest); printf("%s\n\n", strncpy(dest, "C#", 2)); # 함수호출 strncpy(dest, "C#", 2)의 결과는 "C#" dest에 2byte만 복사한 후, # 반환값은 문자 포인터 dest 임 printf("%s\n", strncpy(dest, "c#", 3)); # 함수호출 strncpy(dest, "C#", 3)의 결과는 "C#" dest에 3byte까지 복사하므로 # 마지막은 null 문자가 복사되며, 반환값은 문자 포인터 dest 임 printf("%d\n", strncpy_s(dest, 80, "C#", 3)); printf("%s\n", dest);
C is a language. 0 C is a language. C#is a language. c# 0 C#
함수 strcat()
- 하나의 문자열 뒤에 다른 하나의 문자열을 연이어 추가해 연결한다.
- 함수 strcat()는 앞 문자열에 뒤 문자열의 null 문자까지 연결하여, 앞의 문자열 주소를 반환하는 함수이다.
- 앞 인자인 dest의 저장공간이 연결된 문자열의 길이를 모두 수용할 수 있는 공간보다 부족하면 문제가 발생한다.
- 문제를 예방하기 위한 함수가 strncat() 함수이다.
- strncat() 함수는 전달인자의 마지막에 연결되는 문자의 수를 지정하여 그 이상은 연결되지 않도록 한다. 여기서 지정하는 문자 수는 null문자를 제외한 수이다.
char * strcat(char * dest, const char * source); 앞 문자열 dest에 뒤 문자열 source를 연결(concatenate)해 저장하며, 이 연결된 문자열을 반환하고 뒤 문자열은 수정될 수 없다. char * strncat(char * dest, const char * source, size_t maxn); 앞 문자열 dest에 뒤 문자열 source중에서 n개의 크기만큼을 연결(concatenate)해 저장하며, 이 연결된 문자열을 반환하고 뒤 문자열은 수정될 수 없다.
지정한 maxn이 문자열 길이보다 크면 null 문자까지 연결한다.errno_t strcat_s(char * dest, size_t sizedest, const char *source);
errno_t strncat_s(char * dest, size_t sizedest, const char * source, size_t maxn);두 번째 인자인 sizedest는 정수형으로 dest의 크기를 입력한다.
반환형 errno_t는 정수형이며 반환값은 오류번호로 성공하면 0을 반환한다.
Visual C++에서는 앞으로 함수 strcat_s()와 strncat_s()의 사용을 권장한다.char d[] = "C C++"; char s[] = "Java"; strcat(d, s); # 결과는 d에도 "C C++Java"가 저장된다.
char dest[80] = "C"; printf("%s\n", strcat(dest, " is ")); printf("%d\n", strcat_s(dest, 80, " is ")); printf("%s\n\n", dest); printf("%s\n", strncat(dest, "a java", 2)); printf("%d\n", strncat_s(dest, 80, "a proce", 2)); printf("%s\n\n", dest); printf("%s\n", strcat(dest, "procedural ")); printf("%s\n", strcat(dest, "language."));
C is 0 C is is C is is a 0 C is is a a C is is a a procedural C is is a a procedural language.
문자열 분리 및 다양한 문자열 관련 함수
함수 strtok()
- 문자열에서 구분자(delimiter)인 문자를 여러 개 지정하여 토큰을 추출하는 함수
- 함수 strtok()에서 첫 번째 인자인 str은 토큰을 추출할 대상인 문자열이며 두 번째 인자인 delim은 구분자로 모임인 문자열이다.
- 첫 번째 인자인 str은 문자배열에 저장된 문자열을 사용해야 한다.
- str은 문자열 상수를 사용할 수 없다.
char * strtok(char * str, const char * delim); 앞 문자열 str에서 뒤 문자열 delim을 구성하는 구분자를 기준으로 순서대로 토큰을 추출하여 반환하는 함수이며, 뒤 문자열 delim은 수정될 수 없다. char * strtok_s(char * str, const char * delim, char ** context); 마지막 인자인 context는 함수 호출에 사용되는 위치 정보를 위한 인자이며, Visual C++에서는 앞으로 함수 strtok_s()의 사용을 권장한다. 문자열 : "C and C++\t language are best!" - 구분자 delim이 " "인 경우의 토큰 : C, and, C++\t, language, are, best! 총 6개 - 구분자 delim이 " \t"인 경우의 토큰 : C, and, C++, language, are, best! 총 6개 - 구분자 delim이 " \t!"인 경우의 토큰 : C, and, C++, language, are, best 총 6개 함수 strtok()의 사용방법
- 문장 ptoken = strtok(str, delimiter);으로 첫 토큰을 추출한다.
- 결과를 저장한 ptoken이 NULL이면 더 이상 분리할 토큰이 없는 경우이다.
- 계속 토큰을 추출하려면 while 반복으로 추출된 토큰이 있는지를 (ptoken != NULL)로 검사하고 NULL을 첫 번째 인자로 다시 strtok(NULL, delimiter)를 호출하면 그 다음 토큰을 반환 받을 수 있다.
char *ptoken[100] = { "\0" }; ptoken[0] = strtok(txt, " "); while (ptoken[i++]) { ptoken[i] = strtok(NULL, " ") }
문자열의 길이와 위치 검색
- strlen() : NULL 문자를 제외한 문자열 길이를 반환하는 함수
- strlwr() : 인자를 모두 소문자로 변환하여 반환하는 함수
- strupr() : 인자를 모두 대문자로 변환하여 반환하는 함수
char * strlwr(char * str);
errnot_t _strlwr_s(char * str, size_t strsize); // Visual C++ 권장함수문자열 str을 모두 소문자로 변환하고 변환한 문자열을 반환하므로 str은 상수이면 오류가 발생하며, errno_t는 정수형의 오류번호이며, size_t도 정수형으로 strsize는 str의 길이 char * strupr(char * str);
errnot_t _strupr_s(char * str, size_t strsize); // Visual C++ 권장함수문자열 str을 모두 대문자로 변환하고 변환한 문자열을 반환하므로 str은 상수이면 오류가 발생하며, errno_t는 정수형의 오류번호이며, size_t도 정수형으로 strsize는 str의 길이 char * strpbrk(const char * str, const char * charset); 앞의 문자열 str에서 문자열 charset에 포함된 문자가 나타나는 처음 위치를 찾아 그 주소값을 반환한다.
만일 찾지 못하면 NULL 포인터를 반환char * strstr(const char * str, const char * strsearch); 앞의 문자열 str에서 뒤 문자열 strsearch이 나타나는 처음 위치를 찾아 그 주소값을 반환한다.
만일 찾지 못하면 NULL 포인터를 반환char * strchr(const char * str, char ch); 앞의 문자열 str에서 뒤 문자 ch가 나타나는 처음 위치를 찾아 그 주소값을 반환한다.
만일 찾지 못하면 NULL 포인터를 반환문자열을 역순으로 저장하는 함수 reverse() 구현
void reverse(char str[]) { for (int i = 0, j = strlen(str) - 1; i < j; i++, j--) { char ch = str[i]; str[i] = str[j]; str[j] = ch; } }
문자 포인터 배열과 이차원 문자 배열
문자 포인터 배열
- 여러 개의 문자열을 처리하는 하나의 방법은 문자 포인터 배열을 이용
- 하나의 문자 포인터가 하나의 문자열을 참조 가능
- 문자 포인터 배열은 여러 개의 문자열을 참조 가능
char *pa[] = {"JAVA", "C#", "C++"}; # 각각의 3개 문자열 출력 printf("%s ", pa[0]); printf("%s ", pa[1]); printf("%s ", pa[2]);
- 장점 : 문자 포인터 배열 이용 방법은 각각의 문자열 저장을 위한 최적의 공간을 사용하는 장점을 갖는다.
- 단점 : 문자 포인터를 사용해서는 문자열 상수의 수정은 불가능하다
- 즉 문장 pa[0][2] = ‘v’;와 같이 문자열의 수정은 실행오류가 발생
- 문자 포인터 배열 pa를 이용하여 각 문자열을 출력하려면 pa[i]로 형식제어문자 %s를 이용
이차원 문자 배열
- 여러 개의 문자열을 처리하는 다른 방법은 문자의 이차원 배열을 이용
- 배열선언에서 이차원 배열의 열 크기는 문자열 중에서 가장 긴 문자열의 길이보다 1 크게 지정해야 한다.
- 가장 긴 문자열 "java"보다 1이 큰 5를 2차원 배열의 열 크기로 지정
- 이차원의 배열의 행의 크기는 문자열 수에 해당하므로 3으로 지정하거나 공백으로 비워 둠
char ca[][5] = {"JAVA", "C#", "C++"}; # 각각의 3개 문자열 출력 printf("%s ", ca[0]); printf("%s ", ca[1]); printf("%s ", ca[2]);
- 장단점
- 문자의 이차원 배열에서 모든 열 수가 동일하게 메모리에 할당된다.
- 이차원 문자열 배열을 사용한 문자열 처리는 문자열을 수정할 수 있다.
- ca[0][2] = ‘v’;와 같이 원하는 문자 수정이 가능
- 단점 : 여러 문자 열의 길이가 서로 다른 경우에는 '\0' 문자가 들어가 낭비되는 메모리 공간이 있을 수 있다.
03 명형행 인자
main(int argc, char *argv[ ])
- 도스명령어 dir를 프로그램으로 개발한다면 옵션 “/w” 등은 어떻게 인식할까?
- 명령행 인자(command line arguments)를 사용법 : 명령행에서 입력하는 문자열을 프로그램으로 전달하는 방법
- 프로그램에서 명령행 인자는 main() 함수의 인자로 기술
- 명령행 인자를 이용하지 않고 main()의 인자를 void로 기술하였다.
- 프로그램에서 명령행 인자를 받으려면 두 개의 인자 argc와 argv를 (int argc, char * argv[ ])로 기술
- 매개변수 argc : 명령행에서 입력한 문자열의 수
- argv[ ] : 명령행에서 입력한 문자열을 전달 받는 문자 포인터 배열
- 실행 프로그램 이름도 하나의 명령행 인자에 포함
비주얼 스튜디오에서 명령행 인자를 설정
- 메뉴 [프로젝트/{프로젝트이름} 속성…]를 누르거나 – 단축 키 Alt+F7을 눌러 다음 대화상자에서 설정
- 대화상자 [{프로젝트이름} 속성 페이지]의 항목 [디버깅]을 누르고
- 중간의 [명령 인수] 의 입력 상자에 인자를 기술
- 이 입력 상자에는 실행파일 이름 뒤의 옵션만을 기술
#include <stdio.h> int main(int argc, char * argv[]) { printf("실행 명령행 인자(command line arguments) >>\n"); printf("argc = %d\n", argc); for (int i = 0; i < argc; i++) printf("argv[%d] = %s\n", i, argv[i]); return 0; }
실행 명령행 인자(command line arguments) >> argc = 4 argv[0] = D:\KNU\3_1\프로그래밍기초\0511\0511\sum.exe argv[1] = Python argv[2] = 0123 argv[3] = kotlin
'C' 카테고리의 다른 글
[C] QnA 20 (0) 2023.06.09 [C] 구조체와 공용체 (0) 2023.05.18 [C] 문자와 문자열① (0) 2023.05.11 [C] 포인터② (0) 2023.05.09 [C] 포인터① (1) 2023.05.04