프로그래밍 언어/[ C ]

[ C ] 02. 문자열 관련 자주 쓰이는 함수

kim.svadoz 2020. 8. 13. 09:58
728x90
반응형

[ atoi, atof, atol ]


1. atoi, atof, atol 함수의 기원

atoi 함수를 살펴보면 a - to - i 이렇게 나눌 수 있다. a=char(AScII), i = int

  • atoi (char to int) = 문자열을 정수 타입으로
  • atof (char to double) = 문자열을 실수 타입으로
  • atol (char to long int) = 문자열을 long 정수 타입으로

중요한 것은 여기서 char는 char[N], char*로 표현이 되는 문자열을 말한다. // ( char * to int )가 더 정확한 표현같음?

C++에서는 string클래스에 의해서 문자열을 string으로 표현할 수 있는데, C언어에서는 string클래스가 존재하지 않기 때문에 char배열을 이용하여 문자열 표현하기 때문이다.

2. atoi, atof, atol 함수의 원형

include <stdlib.h>
include <cstdlib>

int atoi(const char* cStr);
double atof(const char* cStr);
long int atol(const char* cStr);

cStr이라고 적은 이유는 C스타일의 문자열이라는 것을 강조하기 위해서!

C++의 string을 이용했다면 c_str() 함수를 이용해서 C스타일의 문자열로 변환해서 이용해야한다.

3. atoi, atof, atol 함수사용법

#include <stdlib.h>
#include <stdio.h>

int main(){
    int num = 0;
    char cStr[30] = "2019";

    //문자열 타입으로 출력.
    printf("char* = %s\n", cStr);

    //char* -> int
    num = atoi(cStr);

    //숫자 타입으로 출력
    printf("int = %d\n", num);

    system("pause");
    return 0;
}
// 출력 결과
char* = 2019
int = 2019

4. 숫자가 아닌 문자를 숫자로 바꾸려 한다면?

char 타입을 int로 바꾸려고 하는데, 항상 다 숫자가 들어가있지는 않을거다.

char[]안에 문자가 섞여서 들어간다면...??

#include<iostream>
#include<cstdlib>
using namespace std;
int main(void){
    char str1[] = "BlockDMask";        // 문자열만 있는 경우
    char str2[] = "2019";            // 숫자만 있는 경우
    char str3[] = "2019BlckDMask";    // 숫자 + 문자
    char str4[] = "BlockDMask2019"; // 문자 + 숫자

    cout << "atoi(\"문자만\"); - " << atoi(str1) <, endl;
    cout << "atoi(\"숫자만\"); - " << atoi(str2) <, endl;
    cout << "atoi(\"숫자 + 문자\"); - " << atoi(str3) <, endl;
    cout << "atoi(\"문자 + 숫자\"); - " << atoi(str4) <, endl;
    return 0;
}
# 결과
atoi("BlockDMask")            : 0
atoi("2019")                : 2019
atoi("2019BlockDMask")        : 2019
atoi("BlockDMask2019")        : 0
  1. atoi("문자") : 문자가 맨처음 나왔기 때문에 0 반환
  2. atoi("숫자") : 숫자를 반환
  3. atoi("숫자+문자") : 문자가 나오기 전까지의 숫자 반환
  4. atoi("문자+숫자") : 문자가 바로나오기 때문에 0 반환

atoi() 함수의 원리는 매개변수로 들어온 문자열을 앞에서 부터 읽어서, "공백", or "숫자가 아닌 문자"가 올때까지 숫자로 변환을 해주는 원리이다

5. atoi("문자") vs atoi("0")의 구분에 대해서

그렇다면 atoi("문자")의 반환이 0이라면 atoi("0")과 결과값과 똑같을까?

둘바 반환값은 0이나오지만 숫자"0"이냐, 문자"0"이냐의 차이이다. 이런경우에는 비효율적이지만 isdigit()을 이용해서 판단해주자

문자열의 길이가 1이고 맨앞의 문자가 isdigit('0')으로 true라면 숫자 0인것이고

isdigit('B')이 false라면 문자열로 이루어진 문자라고 판단할 수 있을 것!!

[ strcpy, strncpy ]


예제

// ===================================== strcpy =========================================
#include <stdio.h>
#include <string.h>

int main(void){
    char origin[] = "BlockDMask";        // "BlockDMask\0" 이므로 size = 11;
    char dest1[20];
    char dest2[10];
    char dest3[] = "STRCPY_EXAMPLE";    // size = 15;

    // case1 : 빈 배열에 전체를 복사
    strcpy(dest1, origin);

    // case2 : 꽉 차있는 배열에 전체를 복사
    strcpy(dest2, origin);            // **run time error

    // case3 : 꽉 차있는 배열에 전체를 복사
    strcpy(dest3, origin);

    printf("case1 : %s\n", dest1);
    //printf("case2 : %s\n", dest2);
    printf("case3 : %s\n", dest3);
    return 0;
}
# 출력 결과
case1 : BlockDMask
case3 : BlockDMask
// ===================================== strncpy =========================================
#include <stdio.h>
#include <string.h>

int main(void){
    char origin[] = "BlockDMask";        // "BlockDMask\0" 이므로 size = 11;
    char dest1[20];
    char dest2[] = "abcdefghijklmnop";    // size = 17;
    char dest3[] = "STRNCPY_EXAMPLE";    // size = 16;
    char dest4[10];

    // case1 : 빈 배열에 전체를 복사
    strncpy(dest1, origin, sizeof(origin));

    // case2 : 꽉 차있는 배열에 전체를 복사
    strncpy(dest2, origin, sizeof(origin));            // **run time error

    // case3 : 꽉 차있는 배열에 일부만 복사
    strncpy(dest3, origin, 4);

    // case4 : 빈 배열에 일부만 복사
    strncpy(dest4, origin, 4);

    printf("case1 : %s\n", dest1);
    printf("case2 : %s\n", dest2);
    printf("case3 : %s\n", dest3);
    printf("case4 : %s\n", dest4);
    return 0;
}
# 출력 결과
case1 : blockDMask
case2 : blockDMask
case3 : BlockCPY_EXAMPLE
case4 : Block쓰레기쓰레기쓰레기쓰레기BlocCPY_EXAMPLE

주의 해야할 것!!

  • strcpy는 문자열 끝(= "\0")까지 복사를 한다.

    => 따라서 strcpy를 통해 배열의 끝인 \0까지 복사가 되면 dest문자열의 N번째 인덱스에 \0이 존재하게 된다. 그러므로 그 문자열은 \0까지 인식하게 되고 프린트를 하게 되면 그 전까지만 출력이 나오는 거다!!

  • strncpy로 복사했을 경우 n의 길이를 주의해야한다.

    strncpy(dest, origin, n)
    n의 크기는 sizeof(origin)보다 작거나 같아야 한다.(휴먼에러 발생할 수 있음)
        - n <= sizeof(origin)
    또한, dest의 길이보다 n은 작거나 같아야 한다.
        - n <= sizeof(dest)

[ strtoull ]

unsigned long long strtoull(const char *nptr, char ** endptr, int base);
    // 정수로 구성한 문자열로 unsigend long long 형식 값 계산
    // *nPtr : 변환할 NULL 종료 문자열
    // **endptr : 검색을 중지하는 문자에 대한 포인터
    // base : 사용할 기수

strtoull 함수는 정수로 구성한 문자열을 계산하여 unsigned long long 형식 값을 반환한다. 그리고 계산할 수 없는 문자를 발견하면 두 번째 입력 인자로 받은 endptr이 가리키는 곳에 설정한다. 특히 세번째 인자로 진수를 선택하면 문자열의 정수를 입력한 진수 체계로 판단하여 계산한다.

Return Value

strtoull은 변환된 값(있는 경우)을 반환하거나 오버플로가 발생할 경우 ULLONG_MAX를 반환한다. 변환을 수행할 수 없는 경우 strtoull은 0을 반환한다. wcstoull또는 유사값을 strtoull로 반환한다. 두 함수 모두 오버플로 또는 언더플로가 발생하는 경우 errno또는 ERANGE로 설정한다.

  • strtoull은 숫자의 일부분으로 인식할 수 없는 첫 번째 문자에서 문자열 nptr읽기를 중지한다. 이 문자는 종료 null문자일 수도 있고 base보다 크거나 같은 첫 번째 숫자일 수도 있다. 로캘은 LC_NUMERIC범주 설정은 nptr의 기 하문자를 인식하도록 결정한다. strtoullwcstoull은 현재 로캘을 사용한다.
  • endptr이 NULL이 아닌 경우 검색을 중지 한 문자에 대한 포인터는 endptr이 가리키는 위치에 저장된다. 올바른 숫자를 찾을수 없거나 잘못된 밑수를 지정하여 변환을 수행할 수 없는 경우 nptr의 값은 endptr이 가리키는 위치에 저장된다.
static int t_tw_i2c_write(AMBA_SHELL_PRINT_f print_f, int argc, char **argv, char *hexString)
{
    int rval = 0;
    unsigned long value;

    void I2c_Write_Word(unsigned char mSlave, unsigned char mReg, unsigned char mData, int i2cDataSize);

    AmbaPrint("input argument hexString ::: %s", hexString);

    value = strtoull(hexString, argv, 16);
    AmbaPrint("value : %u", value);
    // 입력 : 0x00 ~ 0xFE ( 문자열 )
    // 출력 : 0x00 ~ 0xFE ( unsigned char )

    I2c_Write_Word(I2C_SLAVE, I2C_REG, value, I2C_SIZE);
    return rval;
}
728x90
반응형