9-1 判断字符的类型及原理的剖析
include/io_utils.h
#ifndef BASICC_IO_UTILS_IO_UTILS_H_
#define BASICC_IO_UTILS_IO_UTILS_H_
#include <stdio.h>
#include <limits.h>
void PrintBinary(unsigned int value);
#define PRINT_METADATA
#ifdef PRINT_METADATA
# define PRINTLNF(format, ...) printf("("__FILE__":%d) %s: "format"\n", __LINE__, __FUNCTION__ , ##__VA_ARGS__)
#else
# define PRINTLNF(format, ...) printf(format"\n", ##__VA_ARGS__)
#endif
#define PRINT_CHAR(char_value) PRINTLNF(#char_value": %c", char_value)
#define PRINT_WCHAR(char_value) PRINTLNF(#char_value": %lc", char_value)
#define PRINT_INT(int_value) PRINTLNF(#int_value": %d", int_value)
#define PRINT_LONG(long_value) PRINTLNF(#long_value": %ld", long_value)
#define PRINT_LLONG(long_value) PRINTLNF(#long_value": %lld", long_value)
#define PRINT_BINARY(int_value) PrintBinary((unsigned int) int_value);
#define PRINT_HEX(int_value) PRINTLNF(#int_value": %#x", int_value)
#define PRINT_BOOL(bool_value) PRINTLNF(#bool_value": %s", bool_value ? "true" : "false")
#define PRINT_DOUBLE(double_value) PRINTLNF(#double_value": %g", double_value)
#define PRINT_STRING(string_value) PRINTLNF(#string_value": %s", string_value)
#define PRINT_ARRAY(format, array, length) \
do { int array_index; \
for (array_index = 0; array_index < length; ++array_index) { \
printf(format, array[array_index]); \
};\
printf("\n"); } while(0)
#define PRINT_INT_ARRAY_LN(array, length) \
do { int i; \
for (i = 0; i < length; ++i) { \
PRINTLNF(#array"[%d]: %d", i, array[i]); \
}} while(0)
#define PRINT_INT_ARRAY(array, length) PRINT_ARRAY("%d, ", array, length)
#define PRINT_CHAR_ARRAY(array, length) PRINT_ARRAY("%c, ", array, length)
#define PRINT_DOUBLE_ARRAY(array, length) PRINT_ARRAY("%g, ", array, length)
#endif //BASICC_IO_UTILS_IO_UTILS_H_
01.character_type.c
#include <io_utils.h>
#include <ctype.h>
int IsDigit(char c) {
return c >= '0' && c <= '9';
}
int main() {
PRINT_INT(isdigit('0'));
PRINT_INT(isspace(' '));
PRINT_INT(isalpha('a'));
PRINT_INT(isalnum('f'));
PRINT_INT(isalnum('1'));
PRINT_INT(ispunct(','));
return 0;
}
9-2 字符串与其他数值类型的转换
- strtol、strtoll:将字符串转换为有符号整型
- strtoul、strtoull:将字符串转换为无符号整型
- strtof、stptod、strtold:将字符串转换为浮点型
- strtoimax、stptoumax:将字符串转换为所在环境中表示范围最大的整型intmax_t、无符号整型uintmax.t,与前面不同的是,这两个函数定义在stdint.h当中
atoX:使用简单,适用于简单,要求不高的场景
strtoX:可重复解析,更安全,功能更强大
02.conversion.c
#include <io_utils.h>
#include <stdlib.h>
#include <errno.h>
int main() {
// PRINT_INT(atoi("1234")); // 1234
// PRINT_INT(atoi("-1234")); // -1234
// PRINT_INT(atoi(" 1234abcd")); // 1234
// PRINT_INT(atoi("0x10")); // 0
//
// PRINT_DOUBLE(atof("12.34")); // 12.34
// PRINT_DOUBLE(atof("-12e34")); // -1.2e+35
// PRINT_DOUBLE(atof(" 1.234abcd")); // 1.234
// PRINT_DOUBLE(atof("0x10")); // 16
// PRINT_DOUBLE(atof("0x10p3.9")); // 128
char const *const kInput = "1 200000000000000000000000000000 3 -4 5abcd bye";
PRINTLNF("Parse: %s", kInput);
char const *start = kInput;
char *end;
while (1) {
errno = 0;
const long i = strtol(start, &end, 10);
if (start == end) {
break;
}
printf("'%.*s'\t ==> %ld.", (int)(end - start), start, i);
if (errno == ERANGE) {
perror("");
}
putchar('\n');
start = end;
}
PRINTLNF("Left: %s", end);
return 0;
}
9-3 字符串的长度与比较
03.string_length_compare.c
#include <io_utils.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include <string.h>
void SwapString(char * *first, char * *second) {
char * temp = *first;
*first = *second;
*second = temp;
}
void Shuffle(char * *array, int length) {
srand(time(NULL));
for (int i = length - 1; i > 0; --i) {
int random_number = rand() % i;
SwapString(array + i, array + random_number);
}
}
char * *Partition(char * *low, char * *high) {
char * pivot = *(low + (high - low) / 2);
char * *p = low;
char * *q = high;
while (1) {
while (strcmp(*p,pivot) < 0) p++;
while (strcmp(*q, pivot) > 0) q--;
if (p >= q) break;
SwapString(p, q);
}
return q;
}
void QuickSort(char * *low, char * *high) {
if (low >= high) return;
char * *partition = Partition(low, high);
QuickSort(low, partition - 1);
QuickSort(partition + 1, high);
}
int main() {
char *string = "Hello World!";
PRINT_INT(strlen(string));
//PRINT_INT(strnlen_s(string, 100)); // C11, msvc
//PRINT_INT(strnlen(string, 100)); // gcc
char *left = "Hello World!";
char *right = "Hello C Programmers!";
PRINT_INT(strcmp(left, right));
PRINT_INT(strncmp(left, right, 5));
// int array[];
char *names[] = {
"Cindy",
"Don",
"Andrey",
"Elsa",
"George",
"Frank",
"Benny",
};
QuickSort(names, names + 6);
PRINT_ARRAY("%s, ", names, 7);
return 0;
}
9-4 查找字符与子串
04.find_char_and_substring.c
#include <io_utils.h>
#include <string.h>
int main() {
char *string = "Hello World!";
char *result = strchr(string, 'l');
char *result_reverse = strrchr(string, 'l');
puts(result);
puts(result_reverse);
char *substring_position = strstr(string,"Wor");
puts(substring_position);
PRINT_INT(substring_position - string);
char *string2 = "C, 1972; C++, 1983; Java, 1995; Rust, 2010; Kotlin, 2011";
char *break_set = ",;";
int count = 0;
char *p = string2;
do {
p = strpbrk(p, break_set);
if (p) {
puts(p);
p++;
count++;
}
} while (p);
PRINTLNF("Found %d characters.", count);
return 0;
}
9-5 字符串的拆分
05.string_tokenize.c
#include <io_utils.h>
#include <string.h>
#include <stdlib.h>
int main() {
char string[] = "C, 1972; C++, 1983; Java, 1995; Rust, 2010; Kotlin, 2011";
typedef struct {
char *name;
int year;
} Language;
const char *language_break = ";";
const char *field_break = ",";
int language_capacity = 3;
int language_size = 0;
Language *languages = malloc(sizeof(Language) * language_capacity);
if (!languages) {
abort();
}
char *next = strtok(string, field_break);
while (next) {
Language language;
language.name = next;
next = strtok(NULL, language_break);
if (next) {
language.year = atoi(next);
if(language_size + 1 >= language_capacity) {
language_capacity *= 2;
languages = realloc(languages, sizeof(Language) * language_capacity);
if (!languages) {
abort();
}
}
languages[language_size++] = language;
next = strtok(NULL, field_break);
}
}
PRINTLNF("languages: %d", language_size);
PRINTLNF("languages capacity: %d", language_capacity);
for (int i = 0; i < language_size; ++i) {
PRINTLNF("Language[name=%s, year=%d]", languages[i].name, languages[i].year);
}
free(languages);
return 0;
}
9-6 字符串的连接和复制
06.string_concat_copy.c
#include <io_utils.h>
#include <string.h>
int main() {
char src[] = "HelloWorld";
char dest[20] = "C said: ";
//strcat(dest, src);
strcpy(dest + strlen(dest), src);
puts(dest);
return 0;
}
9-7 几个常见的内存操作函数
07.mem_op.c
#include <io_utils.h>
#include <string.h>
#include <stdlib.h>
int main() {
// memchr()
// strchr()
// memcmp()
// strcmp()
//memset()
char *mem = malloc(10);
memset(mem, 0, 10);
PRINT_INT_ARRAY(mem, 10);
free(mem);
//memcpy
//strcpy
//memmove()
char src[] = "HelloWorld";
char *dest = malloc(11);
memset(dest, 0, 11);
memcpy(dest, src, 11);
puts(dest);
memcpy(dest + 3, dest + 1, 4);
puts(dest);
free(dest);
return 0;
}
9-8 C99的restrict
一个可以重叠,一个是不重叠的
08.restrict.c
#include <io_utils.h>
#include <string.h>
#include <stdlib.h>
int main() {
char *mem = malloc(10);
memset(mem, 0, 10);
PRINT_INT_ARRAY(mem, 10);
free(mem);
char *left = "Hello World!";
char *right = "Hello C Programmers!";
PRINT_INT(strcmp(left, right));
PRINT_INT(strncmp(left, right, 5));
char src[] = "HelloWorld";
char *dest = malloc(11);
memset(dest, 0, 11);
memcpy(dest, src, 11);
puts(dest);
memcpy(dest + 3, dest + 1, 4);
puts(dest);
free(dest);
return 0;
}
9-9 C11的安全版本的函数
加【*_s】增加的安全检查
09.safe_version.c
#define __STDC_WANT_LIB_EXT1__ 1
#include <io_utils.h>
#include <string.h>
#include <stdlib.h>
int main() {
//定义支不支持这些函数
#ifdef __STDC_LIB_EXT1__
puts("support C11 safe version.");
#else
puts("No support for C11 safe version.");
#endif
char dst[2];
int error_no = strcpy_s(dst, 2, "Too long!");
PRINT_INT(error_no); // 34
if (error_no) {
perror("strcpy_s returns: "); // strcpy_s returns: : Result too large
}
return 0;
}
9-10 宽字符串与窄字符串的转换
Lunux系统基本上都是UTF-8,windows系统基本上都是GBK,所以在跨平台的时候需要注意编码问题。
10.mbs_wcs.c
#include <io_utils.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
#include <locale.h>
int main() {
// support for wide string
{
PRINT_BOOL(iswalpha(L'A'));
PRINT_BOOL(iswdigit(L'2'));
wchar_t *wcs = L"你好 Hello";
size_t length = wcslen(wcs);
PRINT_INT(length);
wchar_t src[] = L"HelloWorld";s
wchar_t *dest = malloc(sizeof(wchar_t) * 11);
wmemset(dest, 0, 11);
wmemcpy(dest, src, 11);
_putws(dest);
wmemcpy(dest + 3, dest + 1, 4);
_putws(dest);
free(dest);
}
// conversions 编码转换
char *new_locale = setlocale(LC_ALL, "zh_CN.utf8");
if (new_locale) {
puts(new_locale);
}
{
char mbs[] = "你好";
wchar_t wcs[10];
mbstowcs(wcs, mbs, 10);
wprintf(L"%s\n", wcs);
}
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.10.2)
get_filename_component(ProjectId ${CMAKE_CURRENT_SOURCE_DIR} NAME)
string(REPLACE " " "_" ProjectId ${ProjectId})
project(${ProjectId} C)
set(CMAKE_C_STANDARD 11)
#if (MSVC)
# set(CMAKE_C_FLAGS "/utf-8")
#endif ()
include_directories("include")
file(GLOB files "${CMAKE_CURRENT_SOURCE_DIR}/*.c")
foreach(file ${files})
get_filename_component(name ${file} NAME)
add_executable(${name} ${file})
endforeach()