ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [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
Designed by Tistory.