혹시나 문제가 된다면 바로 비공개 처리하겠습니다. 지적이나 댓글 환영합니다!
이번 포스팅에서는 문자열 관련 함수에 관한 내용을 정리하겠다.
참고로, 내가 정의한 libft.h 헤더에는 <unistd.h>와 <stdlib.h>가 include 되어있다. 따라서 libft.h를 호출하면, 따로 정의하지 않고도 <unistd.h> 에 정의된 size_t 타입과 <stdlib.h>의 malloc/free를 사용할 수 있다.
(1) strlen : 문자열 길이 함수
- string + length
- 매뉴얼(영문번역) :
이름 : strlen -- 문자열의 길이를 구한다
라이브러리 : 표준 C 라이브러리 (libc, -lc)
시놉시스 :
#include <string.h>
size_t strlen(const char *s);
설명 : strlen() 함수는 문자열 s의 길이를 연산한다.
리턴값 : strlen() 함수는 문자열 끝의 null 문자가 올 때까지의 문자의 개수를 리턴한다.
- 구현 코드 예시 :
1
2
3
4
5
6
7
8
9
10
11
12
|
#include "libft.h"
size_t ft_strlen(const char *str)
{
size_t len;
len = 0;
while (str[len])
len++;
return (len);
}
|
cs |
- while (str[len]) 은 while (str[len] != '\0')와 동일한 의미이다
- 참고) size_t 란 무슨 타입인가? (주의 ! 엄밀히 unsigned int 타입이 아니다)
size_t는 '이론상 가장 큰 사이즈를 담을 수 있는 unsigned 데이터 타입'으로 정의된다. 즉, 32비트 머신에서는 32비트 사이즈의 unsigned 정수형(int가 아니라 그냥 '정수'를 의미함), 64비트 머신에서는 64비트 사이즈의 unsigned 정수형(unsigned long long)이다. 향후 등장할 지도 모르는 128비트 머신이라던가 더 큰 머신이 존재한다면 그에 따라 더 큰 사이즈가 될 것이다.
따라서 unsigned int로 착각하고 int나 unsigned int로 형변환을 해서 사용하다가 범위가 벗어나는 버그가 발생할 가능성이 있으니 유의해두는 게 좋다. 특히 큰 데이터나 큰 용량을 가진 파일을 처리할 때 주의해야할 것이다.
- 참고) (char *) 과 (cosnt char *)의 차이점
(char *) 은 문자열 상수를 가리키지 못하고, (const char *)은 문자열 상수를 가리키지만 그 주소에 다른 값을 씌울 수는 없다. 결국 둘 다 메모리에 있는 임시 문자열 상수에 대한 변화는 불가능하다는 것이다.
따라서 읽기 전용인 (const char *) 자료형을 함수 매개변수로 문자열을 넘길 때 많이 사용하게 된다
- 참고) (const char) 과 (char const) 의 차이점
(const char *)은 (const char)에 대한 포인터이고, (char * const)는 (char)에 대한 상수 포인터이다.
(const char *)은 상수형 문자에 대한 포인터로서, 포인터가 가리키는 변수의 값을 바꿀 수 없다
(char const *)는 문자에 대한 상수형 포인터로, 포인터 값을 바꿀 수 없다
(const char const *)는 상수형 문자에 대한 상수형 포인터로, 포인터가 가리키는 변수의 값과 포인터 값을 바꿀 수 없다.
(2) strlcpy : 문자열 복사 함수
- string + length + copy
- strcpy와 똑같이 데이터를 복사하지만, 보안 목적으로 strcpy를 대신할 함수로 만들어졌다.
- 매뉴얼(영문번역) :
이름 : strlcpy -- size 범위의 문자열을 복사
라이브러리 : 표준 C 라이브러리 (libc, -lc)
시놉시스 :
#include <string.h>
size_t strlcpy(char * restrict dst, char * restrict src, size_t dstsize);
설명 :
- strlcpy()는 destination 버퍼의 전체 사이즈를 받고,
dstsize - 1만큼의 문자들을 문자열 src에서 문자열 dst로 복사한다
- dstsize가 0이 아닐 경우, 결과값 끝에 null을 넣고 종료시킨다.
- 흔히 오용되곤하는 strncpy 함수를 대체할 수 있다. 더 일관적이며, 안전하고, 오류가 적다.
리턴값 : src의 길이를 리턴한다 (생성하고자 했던 string의 총 길이)
유의점 : strlcpy()는 공간이 있을 경우 null로 끝나는 것을 보장한다.
null을 위한 공간이 dstsize에 포함되어있어야함을 유의해야한다
리턴값이 dstsize보다 작을 경우, 복사한 결과 문자열이 잘릴 수 있다.
- 구현 코드 예시 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
#include "libft.h"
size_t ft_strlcpy(char *dest, const char *src, size_t dstsize)
{
size_t i;
size_t len;
i = 0;
len = ft_strlen(src);
if (dstsize == 0)
return (len);
while (src[i] && i < dstsize - 1)
{
dest[i] = src[i];
i++;
}
dest[i] = '\0';
return (len);
}
|
cs |
- 어떤 경우에나 src의 길이를 리턴한다.
- dstsize - 1 만큼의 문자들을 src에서 dst로 복사한 후, 끝에 null을 넣고 종료시킨다.
- dstsize는 끝의 null을 포함한 길이를 넣어줘야한다
- 참고) strncpy, strlcpy의 차이점
strncpy에서는 src의 길이가 dst 버퍼의 길이와 같거나 더 길 경우, NULL-terminate 되지 않는다. (null 문자로 종료되지 않는다).
반면 strlcpy는 NULL-terminate를 보장한다. 이 함수는 size - 1 만큼의 string 복사와 함께 NULL로 끝남을 보장해준다. 현재 커널에서는 두 함수 모두 많이 사용되고 있다.
또 strncpy는 문자열에 대한 포인터를 반환하지만, strlcpy는 정수형의 길이를 반환한다는 점 또한 차이점이다.
이는 strn 시리즈와 strl 시리즈의 공통적인 차이점이기도 하다.
(3) strlcat : 문자열 결합 함수
- string + length + concatenate
- 매뉴얼(영문번역) :
이름 : strlcat -- size 범위의 문자열을 연결
라이브러리 : 표준 C 라이브러리 (libc, -lc)
시놉시스 :
#include <string.h>
size_t strlcat(char * restrict dst, char * restrict src, size_t dstsize);
설명 :
- strlcat()는 destination 버퍼의 전체 사이즈를 받고, 문자열 dst의 끝에 문자열 src를 붙인다.
이때, 최대 dstsize - strlen(dst) - 1만큼의 문자들을 결합한다.
- dstsize가 0이거나 원본 dst 문자열이 dstsize보다 긴 경우를 제외하면,
결과값 끝에 null을 넣고 종료시킨다.
- 흔히 오용되곤하는 strncat 함수를 대체할 수 있다. 더 일관적이며, 안전하고, 오류가 적다.
리턴값 :
- 원래 dst의 길이 + src의 길이 (생성하고자 했던 문자열의 총 길이)
- src의 길이 (dstsize가 0인 경우)
- dstsize + src의 길이 (dstsize가 원래 dst의 길이보다 작거나 같은 경우)
유의점 : strlcat()는 공간이 있을 경우 null로 끝나는 것을 보장한다.
null을 위한 공간이 dstsize에 포함되어있어야함을 유의해야한다
리턴값이 dstsize보다 작을 경우, 복사한 결과 문자열이 잘릴 수 있다.
- 구현 코드 예시 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
#include "libft.h"
size_t ft_strlcat(char *dest, const char *src, size_t dstsize)
{
size_t i;
size_t len;
len = ft_strlen(dest);
if (dstsize <= len)
return (ft_strlen(src) + dstsize);
i = 0;
while (src[i] && len + i + 1 < dstsize)
{
dest[len + i] = src[i];
i++;
}
dest[len + i] = '\0';
return (ft_strlen(src) + len);
}
|
cs |
- dstsize가 dst의 길이보다 작거나 같은 경우, dstsize와 src의 길이를 더한 값을 리턴한다
- dstsize가 dst길이보다 큰 경우, dst에 총 (dstsize - 1) 개의 문자가 들어갈 때까지 최대한 복사를 수행하고, 끝에 null을 넣어준 다음, 원래 dst의 길이 + src의 길이를 리턴한다
(4) strchr : 문자열 속 문자 탐색 함수
- string + char
- 매뉴얼(영문번역) :
이름 : strchr -- 문자열 속의 어떤 문자의 위치를 찾는다
라이브러리 : 표준 C 라이브러리 (libc, -lc)
시놉시스 :
#include <string.h>
char *strchr(const char *s, int c);
설명 : strchr() 함수는 s가 가리키는 문자열 안에서 (char로 변환된) c가 첫번째로 등장하는 위치를 찾는다.
문자열 끝의 null 문자 또한 문자열의 일부로 간주한다.
그러므로 c가 '\0'일 경우, 함수는 문자열 끝의 '\0'의 위치를 찾는다.
리턴값 : 찾은 문자의 위치를 가르키는 포인터를 반환한다.
만일 문자열에서 그 문자를 찾지 못하면, null을 반환한다
- 구현 코드 예시 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#include "libft.h"
char *ft_strchr(const char *s, int c)
{
size_t i;
i = 0;
if ((unsigned char)c == '\0')
return ((char *)(s + ft_strlen(s)));
while (s[i])
{
if (s[i] == (unsigned char)c)
return ((char *)(s + i));
i++;
}
return (0);
}
|
cs |
- 주의할 점 : (unsigned char) 형으로 비교를 수행
- null 문자 또한 문자열의 일부로 간주하므로, 찾고자 하는 문자가 널 문자일 경우를 미리 예외처리 해주었다.
- 문자열의 맨 앞에서부터 탐색을 수행한다
- 문자열에서 찾은 특정 문자의 위치를 반환한다.
- 문자열에서 해당 문자를 찾지 못하면 0을 반환한다.
- (const char *) 형인 s[i] 위치를 리턴하기 위해 (char *)형으로 형변환 한 후 리턴하였다
(5) strrchr : 문자열 속 문자 탐색 함수
- string + reverse + char
- 매뉴얼(영문번역) :
이름 : strrchr -- 문자열 속의 어떤 문자의 위치를 찾는다
라이브러리 : 표준 C 라이브러리 (libc, -lc)
시놉시스 :
#include <string.h>
char *strrchr(const char *s, int c);
설명 : strrchr() 함수는 s가 가리키는 문자열 안에서 (char로 변환된) c가 마지막으로 등장하는 위치를 찾는다.
그 외의 동작은 strchr()함수와 같다.
리턴값 : 찾은 문자의 위치를 가르키는 포인터를 반환한다.
만일 문자열에서 그 문자를 찾지 못하면, null을 반환한다
- 구현 코드 예시 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
#include "libft.h"
char *ft_strrchr(const char *s, int c)
{
size_t i;
size_t len;
len = ft_strlen(s);
if ((unsigned char)c == '\0')
return ((char *)(s + len));
i = 1;
while (i <= len)
{
if (s[len - i] == (unsigned char)c)
return ((char *)(s + len - i));
i++;
}
return (0);
}
|
cs |
- 주의할 점 : (unsigned char) 형으로 비교를 수행
- null 문자 또한 문자열의 일부로 간주하므로, 찾고자 하는 문자가 널 문자일 경우를 미리 예외처리 해주었다.
- 문자열의 맨 뒤에서부터 탐색을 수행한다
- 문자열에서 찾은 특정 문자의 위치를 반환한다.
- 문자열에서 해당 문자를 찾지 못하면 0을 반환한다.
- (const char *) 형인 s[i] 위치를 리턴하기 위해 (char *)형으로 형변환 한 후 리턴하였다
- s[len - 1] (null 문자 바로 전) 부터 s[0]까지 탐색하는데, i = 0으로 설정할 경우, s[len - 1 - i] 로 코드가 복잡해져서 i = 1로 설정하였다.
(6) strnstr : 문자열 속 문자열 탐색 함수
- string + n + string
- 매뉴얼(영문번역) :
이름 : strnstr -- 문자열 속 부분 문자열의 위치를 찾는다
라이브러리 : 표준 C 라이브러리 (libc, -lc)
시놉시스 :
#include <string.h>
char *strnstr(const char *haystack, const char *needle, size_t len);
설명 : strnstr() 함수는 haystack 이라는 문자열 속,
처음으로 등장하는 needle 문자열(null로 끝남)의 위치를 찾는다. 이때 최대 len만큼 문자를 탐색한다.
'\0'(널문자) 이후에 나오는 문자들은 탐색하지 않는다.
리턴값 :
- needle이 빈 문자열일 경우, haystack을 리턴한다;
- 만일 needle이 haystack에 존재하지 않는 경우, null을 리턴한다
- 만약 needle이 haystack에 존재한다면, needle의 첫번째 문자의 위치를 리턴한다
- 구현 코드 예시 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
#include "libft.h"
char *ft_strnstr(const char *haystack, const char *needle,
size_t len)
{
size_t i;
size_t j;
size_t length;
length = ft_strlen(needle);
if (length == 0)
return ((char *)haystack);
i = 0;
while (haystack[i] && i < len)
{
j = 0;
while (needle[j] && i + j < len)
{
if (haystack[i + j] != needle[j])
break ;
j++;
}
if (!(needle[j]))
return ((char *)haystack + i);
i++;
}
return (0);
}
|
cs |
- 최대 len 만큼 문자열을 탐색한다.
- needle이 빈 문자열일 경우(= needle의 길이가 0 일 경우), (char *)로 형변환한 haystack을 리턴하였다.
- haystack에서 needle이 존재하는 경우 (= needle의 끝(null 이전)까지 비교가 수행된 경우), haystack에서 needle이 등장하는 첫 위치를 리턴한다.
- needle이 haystack에 존재하지 않는 경우 0을 리턴하였다.
(7) strncmp : 문자열 비교 함수
- 매뉴얼(영문번역) :
이름 : strncmp -- 문자열들을 비교한다
라이브러리 : 표준 C 라이브러리 (libc, -lc)
시놉시스 :
#include <string.h>
int strncmp(const char *s1, const char *s2, size_t n);
설명 : strncmp() 함수는 null로 끝나는 문자열 s1, s2에서 최대 n개만큼 문자를 비교한다.
strncmp()는 2진수 데이터보다는 문자열을 비교하기 위해 고안되었기 때문에,
'\0'(널문자) 이후의 문자들은 비교되지 않는다
리턴값 : s1이 s2보다 값이 큰 지, 같은 지, 작은 지에 따라 리턴값이 달라진다.
각 경우에 양수, 0, 음수를 반환한다.
비교는 unsigned char을 이용하여 진행되므로, '\200'이 '\0'보다 크다.
- 구현 함수 예시 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#include "libft.h"
int ft_strncmp(const char *s1, const char *s2, size_t n)
{
size_t i;
if (n == 0)
return (0);
i = 0;
while (s1[i] && s2[i] && i + 1 < n)
{
if (s1[i] != s2[i])
break ;
i++;
}
return ((unsigned char)s1[i] - (unsigned char)s2[i]);
}
|
cs |
- 최대 n 개만큼 문자를 비교한다.
- 비교가 (unsigned char)로 수행된 다는 점을 주의하여, s1와 s2의 차이값을 (unsigned char)로 비교하여 리턴하였다.
- (unsigned char) 형의 차이값을 리턴할 때 int 형으로 자동적 형변환이 일어나므로, 굳이 명시적 형변환을 하지 않았다.
- null 문자 이후의 문자들은 비교되지 않는다는 점을 고려하여, while문의 조건으로 s1과 s2가 모두 null이 아닐 때 반복을 수행하게 하였다
참고) C언어 형 변환(캐스팅) 시 주의점
문자(아스키코드, 언어)를 형변환 할 때에는 unsigned char로 캐스팅하는 것이, 이후의 int형 형변환에서 안전하다.
https://swimminglab.tistory.com/69
C 언어 형 변환(캐스팅)시 주의할 점
예를 들어서 11001111이라는 char 형의 데이터가 있다고 하자. 그런데 아스키 코드에 있는 영어만 사용할 것이 아니고 한글을 사용하고 싶은 경우가 있을 수 있다. 참고로 한글은 '가'라는 한 글자를
swimminglab.tistory.com
참고자료 출처 :
https://code4human.tistory.com/112
[C언어] 내장함수 비교 - strlcpy, strlcat
앞서 의 strcpy, strncpy, strlcpy의 차이를 정리했다. 그 중 strlcpy는 strlcat과 유사하다. 실제로 man 가이드는 이 둘을 같이 안내한다. 간단히 차이점을 정리해본다. strlcpy PROTOTYPE #include size_t strl..
code4human.tistory.com
https://noel-embedded.tistory.com/1171
char *과 const char *
char *, const char * 둘의 차이는 문자 상수를 참조할 수 있느냐의 여부에 있다. 다음과 같이 컴파일 에러와 표현되지 않은 식을 보면서 대략 유추할 수 있다 char*은 문자열 상수를 가리키지 못하고, c
noel-embedded.tistory.com
[c++] 항상 헷갈리는 const 위치에 따른 쓰임새 차이 (const char , char const)
■ ( const char * ) 상수형 문자에 대한 포인터. 포인터가 가리키는 변수의 값을 바꿀 수 없음 #include int main() { char ch1 = 'a'; char ch2 = 'b'; const char * pch; pch = &ch1; std::cout << *pch << s..
simplesolace.tistory.com
https://blog.dasomoli.org/478/
[Linux:Kernel] strncpy 대신 strlcpy – DasomOLI는 다솜돌이라구요~!
이 글에 있는 모든 코드는 GPL License를 따릅니다(All code attached is released under the GPL License in this article). strncpy 에서는 source의 길이가 destination의 버퍼 길이와 같거나 더 길 경우, NUL-terminate되지 않는
blog.dasomoli.org
([C언어] 24강) "자동적 형변환"과 "명시적 형변환"
안녕하세요! 잭클입니다! 이번 시간에는 자동적 형변환과 명시적 형변환에 대해서 배울건데요 (약간 늦은 감이 있네요 뒤죽박죽 순서 죄송합니다..ㅠㅠ) 자 우선 어렵지 않으니 바로 코드부터
jeckl.tistory.com
'IT > 42Seoul' 카테고리의 다른 글
[Libft] C 언어 라이브러리 구현_Part2_추가함수 구현2 (0) | 2021.05.23 |
---|---|
[Libft] C 언어 라이브러리 구현_Part2_추가함수 구현1 (0) | 2021.05.23 |
[Libft] C 언어 라이브러리 구현_Part1_malloc을 사용한 함수 (0) | 2021.05.20 |
[Libft] C 언어 라이브러리 구현_Part1_문자 판별 + 변환 관련 함수 (0) | 2021.05.20 |
[Libft] C 언어 라이브러리 구현_Part1_mem관련 함수 (0) | 2021.05.17 |