목차
머리말
저자는 일부 C 언어 기능을 배운 후 문제를 해결할 때 거의 사용하지 않습니다(strlen 제외).몇몇 거물들의 영리한 문제 해결 아이디어와 방법을 관찰한 후 그는 항상 한숨을 쉬었습니다.: 코드를 모두 이해할 수 있습니다 . 나는 이것을한다? 그러다가 사장님 생각대로 다시 하려고 계획했는데, 쓸 수 없다는 걸 알게 됐어요. 이런 초보분들이 적지 않은 것 같아서 여기서 다시 배우고 학습과정을 공유하려고 합니다.
참고: 이 기사에서는 주로 몇 가지 일반적인 문자(문자열) 연산 함수( string )와 메모리 관련 함수(memory ) 를 다루며 , 가장 일반적으로 사용되는 함수만 익히면 되며 필요할 때 다른 함수를 찾아볼 수도 있습니다.
학습 기능을 위한 추천 웹사이트: cplusplus.com
1.strlen 기능
(1) strlen()의 기본 사용법
#include <stdio.h> #include <string.h> int main() { char arr1[] = "abcdefg"; char arr2[] = "abc\0defg"; char arr3[20] = "abcdef"; char arr4[] = { 'a','b','c','d','e','f','g' }; char* arr5 = "abcde"; printf("%d\n", strlen(arr1)); printf("%d\n", strlen(arr2)); printf("%d\n", strlen(arr3)); printf("%d\n", strlen(arr4)); printf("%d\n", strlen(arr5)); return 0; }
함수: strlen() 함수는 문자열에서 '\0'을 제외하고 '\0' 앞에 나타나는 문자 수를 반환합니다. 매개변수가 가리키는 문자열은 '\0'으로 끝나야 정상적인 결과를 반환할 수 있습니다.
(2) strlen()의 반환값 유형int main() { char arr1[] = "abcd"; char arr2[] = "abcdefg"; printf("part1:>"); if (strlen(arr1) - strlen(arr2) < 0) { printf("arr1的长度小于arr2\n"); } else { printf("arr1的长度大于等于arr2\n"); } printf("part2:>"); if ((int)strlen(arr1) - (int)strlen(arr2) < 0) { printf("arr1的长度小于arr2\n"); } else { printf("arr1的长度大于等于arr2\n"); } return 0; }
참고: strlen() 함수를 사용하여 계산된 두 문자열의 길이를 빼면 항상 0보다 크거나 같습니다. strlen() 함수의 반환 값은 우리가 상상했던 int 유형이 아니지만, 부호 없는 유형 size_t
(3) my_strlen() 사용자 정의
自定义my_strlen()函数类型为 int 或 size_t 都可以,但它们各有优缺点 例如:如果为 int 类型,就比较方便理解 strlen(arr1) - strlen(arr2) 这样 的形式,但是如果出现意料之外的错误,就有可能导致计算的字符串长度为负数 //创建临时变量-计数器count int my_strlen1(const char *arr) { assert(arr != NULL); int count = 0; while (*arr != '\0') { count++; arr++; } return count; } //不创建临时变量-递归 int my_strlen2(const char* arr) { assert(arr != NULL); if (*arr != '\0') return 1 + my_strlen2(arr + 1); else return 0; } int main() { char arr[] = "abcdefghijk"; int ret = my_strlen1(arr); printf("%d\n", ret); printf("%d\n", my_strlen2(arr)); return 0; }
2.strcpy 함수
(1) strcpy()의 기본 사용법
매개변수 1: 대상 문자열(수정 가능해야 함), 매개변수 2: 소스 문자열(수정을 방지하기 위해 const 유형으로 정의됨)
下面哪些代码可以正常运行? char arr1_src[] = "abcdef"; char arr1_dest[] = { 0 }; strcpy(arr1_dest, arr1_src); printf("%s\n", arr1_dest); //arr1_dest 所占空间太小 char arr2_src[] = { 'a','b','c','d','e','f' }; char arr2_dest[20] = { 0 }; strcpy(arr2_dest, arr2_src); printf("%s\n", arr2_dest); //arr2_src 中没有 '\0' char arr3_src[] = "abc\0def"; char arr3_dest[20] = { 0 }; strcpy(arr3_dest, arr3_src); printf("%s\n", arr3_dest); //仅成功拷贝 \0 之前的 abc 三个字符 char arr4_src[] = "abcdef"; char* arr4_dest = "qwerty"; strcpy(arr4_dest, arr4_src); printf("%s\n", arr4_dest); //目标空间为 const char 类型,不可被修改 char arr5_src[] = "abcdef"; char arr5_dest[20] = { 0 }; strcpy(arr5_dest, arr5_src); printf("%s\n", arr5_dest); //拷贝成功
기능: 소스 문자열을 복사하여 대상 문자열에 저장합니다. 소스 문자열은 '\0'으로 끝나야 합니다. 소스 문자열의 '\0'은 대상 공간에 복사됩니다. 대상 공간은 충분히 커야 합니다. 소스 문자열을 저장할 수 있는지 확인하세요. 대상 공간은 가변적이어야 합니다.
(2) my_strcpy() 사용자 정의
char* my_strcpy(char* dest, const char* src) { assert(dest && src); char* ret = dest; while (*dest++ = *src++) { ; } return ret; } int main() { char arr1[] = "Practise makes perfect!"; char arr2[30] = { 0 }; my_strcpy(arr2, arr1); printf("%s", arr2); return 0; }
3. strcat 기능
(1) strcat()의 기본 사용법
매개변수 1: 기본 문자열, 매개변수 2: 추가 문자열.
int main() { char arr1_dest[20] = "hello "; char arr1_src[] = "world!"; strcat(arr1_dest, arr1_src); printf("%s\n", arr1_dest); char arr2_dest[20] = "hello \0xxxxxx"; char arr2_src[] = "world!"; strcat(arr2_dest, arr2_src); printf("%s\n", arr2_dest); char arr3_dest[20] = { 'h','e','l','l','o',' '}; char arr3_src[] = "world!"; strcat(arr3_dest, arr3_src); printf("%s\n", arr3_dest); char arr4_dest[20] = "hello "; char arr4_src[] = { 'w','o','r','l','d', '!'}; strcat(arr4_dest, arr4_src); printf("%s\n", arr4_dest); return 0; }
기능: 소스 문자열의 내용('\0' 포함)을 대상 문자열의 '\0' 끝에 연결하여(대상 문자열의 '\0'을 덮음) 대상 공간이 충분히 큰지 확인합니다. 그리고 수정될 수 있습니다.
(2) my_strcat() 사용자 정의
char* my_strcat(char* dest, const char* src) { assert(dest && src); char* ret = dest; while (*dest != '\0') { dest++; } while (*dest++ = *src++) { ; } return ret; } int main() { char arr1[30] = "hello "; char arr2[30] = "world!"; my_strcat(arr1, arr2); printf("%s", arr1); return 0; } 思考: my_strcat(arr1, arr1); 可以达到如下效果吗? arr1 = "hello hello ";
4.strcmp 기능
(1) strcmp()의 기본 사용법
char arr1[] = "compare"; char arr2[] = "compbre"; //可以这样比较字符串的大小吗? if("compare" == "compbre") printf("相等\n"); //这里实际上比较的是它们的地址 //因此这种写法是不能满足我们的需要的 int main() { char arr1[] = "abcde"; char arr2[] = "abcde"; char arr3[] = "abcdabcd"; char arr4[] = "z"; if (strcmp(arr1, arr2) > 0) printf("arr1 > arr2\n"); else if (strcmp(arr1, arr2) == 0) printf("arr1 = arr2\n"); else printf("arr1 < arr2\n"); if (strcmp(arr1, arr3) > 0) printf("arr1 > arr3\n"); else if (strcmp(arr1, arr3) == 0) printf("arr1 = arr3\n"); else printf("arr1 < arr3\n"); if (strcmp(arr1, arr4) > 0) printf("arr1 > arr4\n"); else if (strcmp(arr1, arr4) == 0) printf("arr1 = arr4\n"); else printf("arr1 < arr4\n"); return 0; }
기능: 문자열의 크기를 비교합니다. 먼저 두 문자열의 첫 번째 요소의 ASCII 코드 크기를 비교하고, 같으면 다음 요소를 거꾸로 비교합니다. 두 문자열의 모든 요소가 같으면 다음을 수행할 수 있습니다. 크기를 판단하십시오. 두 문자열이 동일합니다.
(2) my_strcmp() 사용자 정의
int my_strcmp(const char* arr1, const char* arr2) { assert(arr1 && arr2); while (*arr1 == *arr2) { if (*arr1 == '\0') return 0; arr1++; arr2++; } return *arr1 - *arr2; } int main() { char arr1[] = "compare"; char arr2[] = "compbre"; int ret = my_strcmp(arr1, arr2); if (my_strcmp(arr1, arr2) > 0) printf("arr1 > arr2\n"); else if(my_strcmp(arr1, arr2) == 0) printf("arr1 = arr2\n"); else printf("arr1 < arr2\n"); return 0; }
5.str- 및 strn-
(1) 길이가 무제한인 문자열 함수
앞서 소개한 strlen, strcpy, strcmp, strcat 함수에서 매개변수로 사용되는 문자열의 길이에는 제한이 없으므로 다음과 같은 보안 위험이 발생할 수 있습니다.
(2) 길이가 제한된 문자열 함수
길이가 제한된 문자열 함수는 상대적으로 안전할 뿐입니다. 버그를 작성하려는 사람은 누구도 막을 수 없습니다! ! !
strnlen、strncpy、strncmp、strncat
예를 들어:
6.strstr 함수
(1) strstr()의 기본 사용법
매개변수 1: 상위 문자열, 매개변수 2: 하위 문자열.
기능: str2가 str1의 하위 문자열인지 확인하고 str1에서 str2가 처음 나타나는 주소를 반환합니다.
(2) my_strstr() 사용자 정의
char* my_strstr(const char* arr1, const char* arr2) { assert(arr1 && arr2); char* str1 = NULL; char* str2 = NULL; char* p = (char*)arr1; while (*p) { str1 = p; str2 = (char*)arr2; while (*str1 && *str2 && *str1++ == *str2++) { ; } if (*str2 == '\0') return p; p++; } return NULL; } int main() { char arr1[] = "qwereabcd"; char arr2[] = "were"; char* ret = my_strstr(arr1, arr2); if (ret == NULL) { printf("找不到\n"); } else { printf("找到了:%s中存在字符串%s\n", ret, arr2); } return 0; }
(3) strchr 및 strrchr 함수
int main() { char arr1[] = "abcdefgbcde"; char arr2[] = "bcde"; char* ret1 = strchr(arr1, 'b'); if (ret1 == NULL) { printf("找不到\n"); } else { printf("%s\n", ret1); } char* ret2 = strrchr(arr1, 'b'); if (ret2 == NULL) { printf("找不到\n"); } else { printf("%s\n", ret2); } return 0; }
요약: strchr은 대상 문자를 처음 만났을 때의 주소를 반환하고, strrchr은 대상 문자를 마지막으로 만났을 때의 주소를 반환합니다.
7.strtok 기능
(1) strtok()의 기본 사용법
매개변수 1: 분할할 문자열, 매개변수 2: 상수 문자열(분할 문자 집합)
0
기능: 분할할 문자열 세그먼트에 대한 포인터인 "마크"를 반환합니다(원래 문자열을 분할하려면 원래 문자열의 분할 문자를 '\0'으로 변경).
strtok의 첫 번째 매개변수가 NULL이 아닌 경우 함수는 첫 번째 토큰을 반환하고 해당 위치를 문자열에 저장합니다.
strtok의 첫 번째 매개변수가 NULL이면 함수는 저장된 위치에서 시작하여 다음 마크를 검색합니다.
문자열에 더 이상 토큰이 없으면 NULL을 반환합니다.
지금은 strtok 함수 사용법을 배우는 것만으로도 충분하다고 생각합니다
관심 있는 학생들은 스스로 시도해 볼 수 있으며 댓글 영역에서 자신의 my_strtok을 공유할 수 있습니다!
8. 오류 기능
(1) strerror()의 기본 사용법
매개변수: 오류 코드
기능: 오류 코드에 해당하는 오류 메시지의 첫 번째 문자 주소를 반환합니다(오류 코드를 오류 메시지로 변환).
설명: C 언어 라이브러리 함수 호출에 실패하면 errno라는 변수에 오류 코드가 저장됩니다. 어떤 오류가 발생했는지 알고 싶을 때 strerror를 사용하여 오류 코드 errno를 오류 메시지로 변환할 수 있습니다.
다음으로 예를 들어 보겠습니다.
9. 기타 문자열 조작 기능
입력 및 출력 기능
문자열을 읽습니다(공백 포함).
puts는 문자열을 출력합니다.
대소문자 변환 기능
strlwr 소문자로 변환
strupr 대문자로 변환
문자열 검색
strpbrk...
strspn ...
... ...
10. 공통 캐릭터 조작 기능
입력 및 출력 기능
getchar는 문자를 읽습니다.
putchar는 문자를 출력합니다.
대소문자 변환 기능
tolower 소문자로 변환
toupper 대문자로 변환
문자 분류 기능
조건이 충족되면 true를 반환합니다.
isalnum은 문자인지 숫자인지 판별합니다. isdigit
는 숫자인지 판별
합니다. isxdigit는 16진수인지
판별합니다. isalpha는 문자인지 여부를 판별합니다.
isupper는 대문자인지 판별합니다.
islower는 소문자인지 판별합니다. iscntrl은 문자인지
판별합니다. 제어 문자입니다
isspace 공백, 페이지 피드, 줄 바꿈, 캐리지 리턴, 탭 문자인지 확인 ispunct
구두점인지 여부
확인 isgraph 그래픽 문자인지 확인
isprint 인쇄 가능한 문자인지 확인... ...
11.memset 기능
(1) memset()의 기본 사용법
매개변수 1: 수정해야 할 위치를 가리킴(포인터/배열 이름) 매개변수 2: 수정된 데이터 매개변수 3: 수정된 공간의 크기(단위는 바이트)
val은 int 유형입니다.
val은 char 유형입니다.
요약하다:
(1) ptr이 char 유형 주소를 가리키는 경우 value는 모든 문자 값일 수 있습니다.
(2) ptr이 int 유형 주소와 같은 char 유형이 아닌 유형을 가리키는 경우 할당이 정확하려면 값은 - 1 또는 0만 될 수 있습니다. 왜냐하면 - 1과 0이 이진수로 변환된 후에는 각 비트가 동일하므로 우리는 종종 memset을 사용하여 배열을 모두 0으로 초기화합니다.
12.memcpy 함수
(1) memcpy()의 기본 사용법
매개변수 1: 대상 공간에 대한 포인터(void 유형), 매개변수 2: 소스 공간에 대한 포인터(void 유형), 매개변수 3: 복사된 공간의 크기(단위는 바이트)
注意:当我们需要拷贝字符串的时候,是否可以使用memcpy呢?答案是当然可以, 但是我们为什么不直接使用更加方便的strcpy呢? void test1() { int arr1[] = { 1,2,3,4,5,6,7,8,9,10 }; int arr2[20] = { 0 }; memcpy(arr2, arr1, 32); for (int i = 0; arr2[i] != 0; i++) { printf("%d ", arr2[i]); } printf("\n"); } void test2() { float arr1[] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0 }; float arr2[48] = { 0.0 }; memcpy(arr2, arr1, 32); for (int i = 0; arr2[i] != 0; i++) { printf("%.2f ", arr2[i]); } printf("\n"); } int main() { test1(); test2(); return 0; }
(2) my_memcpy() 사용자 정의
void* my_memcpy(void* dest, const void* src, size_t num) { assert(dest && src); void* ret = dest; while (num--) { //我们不知道使用者需要拷贝的类型,所以采用逐字节拷贝的方法 *(char*)dest = *(char*)src; dest = (char*)dest + 1; src = (char*)src + 1; } return ret; } void test3() { int arr1[] = { 1,2,3,4,5,6,7,8,9,10 }; int arr2[20] = { 0 }; my_memcpy(arr2, arr1, 32); for (int i = 0; arr2[i] != 0; i++) { printf("%d ", arr2[i]); } printf("\n"); } int main() { test3(); return 0; }
13.memmove 기능
(1) memmove()의 기본 사용법
매개변수 1: 대상 공간에 대한 포인터(void 유형), 매개변수 2: 소스 공간에 대한 포인터(void 유형), 매개변수 3: 이동된 공간의 크기(단위는 바이트)
다음 코드가 우리가 기대하는 결과를 얻을 수 있습니까?
왜?
참고: 메모리가 겹칠 때 모든 컴파일러가 정상적으로 복사할 수 없는 것은 아니지만 memcpy는 메모리를 덮어쓸 위험이 있습니다!
(2) my_memcpy() 사용자 정의
void* my_memmove(void* dest, const void* src, size_t num) { assert(dest && src); void* ret = dest; if (dest < src) { while (num--) { *(char*)dest = *(char*)src; dest = (char*)dest + 1; src = (char*)src + 1; } } else { while (num--) { *((char*)dest + num) = *((char*)src + num); } } return ret; }
14.memcmp 기능
(1) memcmp()의 기본 사용법
매개변수 1: 비교할 공간의 포인터 1(void 유형), 매개변수 2: 비교할 공간의 포인터 2(void 유형), 매개변수 3: 비교할 공간의 크기(단위는 바이트)
void test1() { int arr1[] = { 1,2,3,4,5,7 }; int arr2[] = { 1,2,3,4,6,7 }; int ret = memcmp(arr1, arr2, 16); printf("%d\n", ret);//0 } void test2() { int arr1[] = { 1,2,3,4,5 }; int arr2[] = { 1,2,3,4,6 }; int ret = memcmp(arr1, arr2, 20); printf("%d\n", ret);//-1 } void test3() { int arr1[] = { 1,2,3,4,5 }; int arr2[] = { 1,2,3,4,6 }; int ret = memcmp(arr1, arr2, 17); printf("%d\n", ret);//-1 } int main() { test1(); test2(); test3(); return 0; }
요약하다
오늘 제가 이야기하고 싶은 내용은 위와 같습니다. 사실 프로그래밍을 배우려면 질문에 답하는 것뿐만 아니라 생각하고 요약하는 것도 필요합니다. 우리는 큰 상사로부터 영감을 얻지 못하는 경우가 많습니다. 우리가 그것을 하기 전에 많은 노력을 기울여야 합니다)), 문제에 직면했을 때 더 많은 방법을 가질 수 있도록 몇 가지 문제 해결 기술과 아이디어를 기록하십시오. 이 글이 모든 분들께 도움이 되기를 바라며, 독자분들의 비판과 지적도 환영합니다^W^