第9章 字符串的应用

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;
}

Ctype中定义的函数

在这里插入图片描述

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()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陶喜儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值