C/C++语言是一种通用的编程语言,具有高效、灵活和可移植等特点。C语言主要用于系统编程,如操作系统、编译器、数据库等;C语言是C语言的扩展,增加了面向对象编程的特性,适用于大型软件系统、图形用户界面、嵌入式系统等。C/C++语言具有很高的效率和控制能力,但也需要开发人员自行管理内存等底层资源,对于初学者来说可能会有一定的难度。

6.1.1 封装字符串操作

字符串与整数: 将字符串转为数值可以使用sscanf()函数,将数值转为字符串可以使用sprintf()函数.

#include #include int main(int argc, char* argv[]){// int -> stringchar szBuf[32] = { 0 };int number = 100;sprintf(szBuf, "%d", number);std::cout << "字符串: " << szBuf << std::endl;// string -> intsscanf(szBuf, "%d", &number);std::cout << "整数: " << number << std::endl;return 0;}

字符串切割: 模拟实现Split()函数对特定字符串使用特定符号进行的切割,切割后的数据分别放入新的数组中.

#include #include #include // 实现字符串切割int split(char dst[][80], char* str, const char* spl){int n = 0;char* result = NULL;result = strtok(str, spl);while (result != NULL){strcpy(dst[n++], result);result = strtok(NULL, spl);}return n;}int main(int argc,char *argv[]){char src_string[] = "what is you name? hello lyshark ?";char dst[10][80];// 以空格进行切割字符串并将结果存入dstint cnt = split(dst, src_string, " ");for (int i = 0; i < cnt; i++){std::cout << "切割后: " << dst[i] << std::endl;}return 0;}

字符串分块: 循环将传入的字符串按照指定长度切片处理,切片后返回到一个二维数组中存储.

#include #include using namespace std;// 实现对字符串指定位置进行剪切char* Cat(char* buffer, int offset, int length){char Split[100] = { 0 };memset(Split, 0, 100);strncpy(Split, buffer + offset, length);return Split;}// 循环剪切字符串int CatSplit(char *buf, char len ,OUT char Split[][1024]){int count = 0;// 每次剪切len大小for (int x = 0; x < strlen(buf); x += len){char* ref = Cat(buf, x, len);strcpy(Split[count], ref);count += 1;}return count;}int main(int argc, char* argv[]){char buf[1024] = "The National Aeronautics and Space Administration";char Split[100][1024] = { 0 };// 切割并获取切割计数器int count = CatSplit(buf, 100, Split);std::cout << "切割次数: " << count << std::endl;// 输出切割计数器for (int x = 0; x < count; x++){std::cout << Split[x] << std::endl;}return 0;}

字符串过滤: 用户传入一个字符串,以及传入需要过滤的字符,自动过滤掉字符串内的所有过滤字符.

#include #include // 删除指定字符void del_char(char Buffer[], char ch){int i, j;for (i = 0, j = 0; *(Buffer + i) != '\0'; i++){if (*(Buffer + i) == ch){continue;}else{*(Buffer + j) = *(Buffer + i);j++;}}*(Buffer + j) = '\0';}void del_char_list(char Buffer[], char list[], int list_count){for (int x = 0; x < list_count; x++){del_char(Buffer, list[x]);}}int main(int argc, char* argv[]){char szBuffer[8192] = "[ 192.168.1.1 , root , 123456 , 22 ]";char del[3] = { '[',']',' '};// 删除列表中的字符del_char_list(szBuffer, del,3);std::cout << "删除后的数据:" << szBuffer << std::endl;return 0;}

字符串替换: 在一个字符串中查找特定字符串,只要找到自动将其替换为新的字符串.

#include #include #include using namespace std;// C语言版 实现字符串替换char* str_replace(char* src, char* rep, char* with){char* index;char* result, * tmp, * next;int count = 0, len_front;int len_with = strlen(with);int len_rep = strlen(rep);next = src;for (count = 0; tmp = strstr(next, rep); ++count){next = tmp + len_rep;}tmp = result = (char*)malloc(strlen(src) + count * (len_rep - len_with) + 1);if (!result)return NULL;while (count--){index = strstr(src, rep);len_front = index - src;tmp = strncpy(tmp, src, len_front) + len_front;tmp = strcpy(tmp, with) + len_with;src += len_front + len_rep;}strcpy(tmp, src);return result;}// C++版string& replace_all_distinct(string& str, const string& old_value, const string& new_value){for (string::size_type pos(0); pos != string::npos; pos += new_value.length()){if ((pos = str.find(old_value, pos)) != string::npos)str.replace(pos, old_value.length(), new_value);elsebreak;}return str;}int main(int argc, char* argv[]){char text[128] = "hello lyshark hello lyshark hello lyshark";char* rep = str_replace(text, (char*)"lyshark", (char*)"abcd");std::cout << "替换后的字符串: " << rep << std::endl;// ---------------------------------------------------------string str = "hello lyshark,hello lyshark, hello,lyshark";string new_str = replace_all_distinct(str, "world", "lyshark");std::cout << "替换后的字符串: " << new_str << std::endl;return 0;}

字符串格式化: 利用可变参数列表,实现类似于Python中的format()函数功能,格式化一段字符串.

#include // 格式化字符串std::string format_string(const char* format, ...){std::string::size_type size = 1024;std::string buffer(size, '\0');char* buffer_p = const_cast<char*>(buffer.data());int expected = 0;va_list ap;while (true){va_start(ap, format);expected = vsnprintf(buffer_p, size, format, ap);va_end(ap);if (expected > -1 && expected < static_cast<int>(size)){break;}else{if (expected > -1)size = static_cast<size_t>(expected + 1);elsesize *= 2;buffer.resize(size);buffer_p = const_cast<char*>(buffer.data());}}return std::string(buffer_p, expected > 0 ? expected : 0);}// 可变参数void print_args(int count, ...){va_list arg_ptr;va_start(arg_ptr, count);for (int x = 0; x < count; x++){int value = va_arg(arg_ptr, int);std::cout << "下标: " << x << " 数值: [ " << value << " ] " << std::endl;}va_end(arg_ptr);}int main(int argc,char *argv[]){// 输出元素数print_args(9, 1, 2, 3, 4, 5, 6, 7, 8, 9);// 格式化并输出for (int x = 0; x < 1000; x++){std::string ref = format_string("address = 192.168.1.%d --> port = %d", x, x+10);std::cout << "生成地址: " << ref << std::endl;}return 0;}

字符串去空格: 函数接收字符串指针,并循环去除该字符串中左右两端的空格,回写到原空间.

#include #include using namespace std;// 去除字符串首尾的空格bool trim(char* szStr){int i = 0, j = 0, iFirst = -1, iLast = -1;int iLen = strlen(szStr);char szTemp[256] = { 0 };// 从前往后遍历,获取第一个不为 空格 的下标for (i = 0; i < iLen; i++){if (' ' != szStr[i]){iFirst = i;break;}}// 从后往前遍历,获取第一个不为 空格 的下标for (i = (iLen - 1); 0 <= i; i--){if (' ' != szStr[i]){iLast = i;break;}}// 字符串全为 空格if (-1 == iFirst || -1 == iLast){return false;}// 获取去除 空格 部分for (i = iFirst; i <= iLast; i++){szTemp[j] = szStr[i];j++;}szTemp[j] = '\0';strcpy(szStr, szTemp);return true;}int main(int argc, char* argv[]){char szBuffer[4096] = "hello lyshark";bool ref = trim(szBuffer);std::cout << "去空格后: " << szBuffer << std::endl;return 0;}

字符串与HEX互转: 将一段字符串转为一段十六进制数(字符串格式),或将十六进制数转为字符串.

#include #include // 将十六进制字符 转 十进制int hexCharToValue(const char ch){int result = 0;if (ch >= '0' && ch <= '9'){result = (int)(ch - '0');}else if (ch >= 'a' && ch <= 'z'){result = (int)(ch - 'a') + 10;}else if (ch >= 'A' && ch <= 'Z'){result = (int)(ch - 'A') + 10;}else{result = -1;}return result;}// 将十进制整数 转 字符char valueToHexCh(const int value){char result = '\0';if (value >= 0 && value <= 9){// 48为ascii编码的0字符编码值result = (char)(value + 48);}else if (value >= 10 && value <= 15){// 减去10则找出其在16进制的偏移量,65为ascii的A的字符编码值result = (char)(value - 10 + 65);}return result;}// 将一段字符串转换为十六进制int strToHex(char* ch, char* hex){int high, low;int tmp = 0;if (ch == NULL || hex == NULL)return -1;if (strlen(ch) == 0)return -2;while (*ch){tmp = (int)*ch;// 取字符的高4位high = tmp >> 4;// 取字符的低4位low = tmp & 15;// 先写高字节*hex++ = valueToHexCh(high);// 其次写低字节*hex++ = valueToHexCh(low);ch++;}*hex = '\0';return 0;}// 将一段十六进制转为字符串int hexToStr(char* hex, char* ch){int high, low;int tmp = 0;if (hex == NULL || ch == NULL)return -1;if (strlen(hex) % 2 == 1)return -2;while (*hex){high = hexCharToValue(*hex);if (high < 0){*ch = '\0';return -3;}// 指针移动到下一个字符上hex++;low = hexCharToValue(*hex);if (low < 0){*ch = '\0';return -3;}tmp = (high << 4) + low;*ch++ = (char)tmp;hex++;}*ch = '\0';return 0;}// 将十六进制字符串 转 byte字节码int hexChartoByte(char* hex, char* byte){int i, n = 0;for (i = 0; hex[i]; i += 2){if (hex[i] >= 'A' && hex[i] <= 'F')byte[n] = hex[i] - 'A' + 10;elsebyte[n] = hex[i] - '0';if (hex[i + 1] >= 'A' && hex[i + 1] <= 'F')byte[n] = (byte[n] << 4) | (hex[i + 1] - 'A' + 10);elsebyte[n] = (byte[n] << 4) | (hex[i + 1] - '0');++n;}return n;}// 将单一字符 转 ascii 码unsigned char ChartoAscii(const unsigned char cha){unsigned char ascii;if ((cha >= 0x0A) && (cha <= 0x0F)){ascii = cha + 'A' - 10;}else{ascii = cha + '0';}return ascii;}int main(int argc, char* argv[]){char hex[1024] = { 0 };char str[1024] = { 0 };char byte[1024] = { 0 };int ref = 0;// 实现字符串与十六进制互转ref = strToHex((char*)"hello lyshark", hex);if (ref == 0){std::cout << "字符串 -> Hex: " << hex << std::endl;}ref = hexToStr(hex, str);if (ref == 0){std::cout << "Hex -> 字符串: " << str << std::endl;}ref = hexChartoByte(hex, byte);if (ref != 0){std::cout << "Hex -> Byte: " << byte << std::endl;}std::cout << "字符 -> Ascii: " << ChartoAscii('12') << std::endl;}

字符串实现拼接: 将单独的字符串拼接为连续的字符串,类似于strcat()功能实现.

#include #include // 组合字符串char *join(const char *a, const char *b){// char *c = (char *)ExAllocatePool(NonPagedPool, strlen(a) + strlen(b) + 1);char *c = (char *)malloc(strlen(a) + strlen(b) + 1);if (c == NULL){return NULL;}char *tempc = c;while (*a != '\0'){*c++ = *a++;}while ((*c++ = *b++) != '\0') { ; }return tempc;}int main(int argc, char *argv[]){char * HttpBuffer;char DataBuffer[128] = {0};char PostData[128] = { 0 };HttpBuffer = join("POST /", "www.lyshark.com");HttpBuffer = join(HttpBuffer, " HTTP/1.1\n");HttpBuffer = join(HttpBuffer, "Host: ");HttpBuffer = join(HttpBuffer, "www.baidu.com");HttpBuffer = join(HttpBuffer, "\n");HttpBuffer = join(HttpBuffer, "Proxy-Connection: keep-alive\n");HttpBuffer = join(HttpBuffer, "User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36 SE 2.X MetaSr 1.0\n");strcpy(PostData, "{a:1,b:2}");sprintf(DataBuffer, "Content-Length: %d\n", (int)strlen(PostData));HttpBuffer = join(HttpBuffer, DataBuffer);HttpBuffer = join(HttpBuffer, "Content-Type: application/x-www-form-urlencoded\n\n");HttpBuffer = join(HttpBuffer, PostData);printf("%s \n", HttpBuffer);return 0;}

字符串实现模拟字典: 通过使用链表结构模拟实现了Python语言中的字典数据结构的基本操作,与字典操作保持一致.

#include #include #include #include  static int N1 = 30;static int N2 = 30;typedef struct Data { char key[30]; char value[30]; }Data;typedef struct Dict{Data data;struct Dict* next;size_t size;}Dict;errno_t append(Dict* dict, const char* key, const char* value);errno_t repair(Dict* dict, const char* key, const char* value);// 初始化Dict* __init__(Dict* dict){if (dict == NULL){dict = (Dict*)calloc(1, sizeof(Dict));dict->size = 0;}elsedict->next = NULL;return dict;}// 删除元素void clear(Dict* dict, const char* key) {Dict* q = dict;Dict* p = dict->next;while (p != NULL){if (strcmp((p->data).key, key) == 0){q->next = p->next;dict->size -= 1;free(p);return;}q = p;p = p->next;}}// 按主键查找Key是否存在Dict* _findkey(Dict* dict, const char* key){Dict* p = dict->next;while (p != NULL){if (strcmp((p->data).key, key) == 0){return p;}p = p->next;}return NULL;}// 将记录按姓名字母升序插入链表 void _insert_n(Dict* dict, Dict* q){Dict* p = dict;while (p->next != NULL && strcmp((p->next->data).key, (q->data).key) < 0){p = p->next;}q->next = p->next;p->next = q;dict->size += 1;}// 释放整个链表空间 void __destroy__(Dict* dict){Dict* p = dict;while (p->next != NULL){p = p->next;free(dict);dict = p;}if (p != NULL)free(p);}// 添加字典元素errno_t append(Dict* dict, const char* key, const char* value){Dict* p, * r; _set_errno(0);if ((r = _findkey(dict, key)) == NULL){// 判断记录是否已存在// 申请Dict空间并初始化p = (Dict*)calloc(1, sizeof(Dict)); if (p != NULL){strcpy_s((p->data).key, N1, key);strcpy_s((p->data).value, N2, value);_insert_n(dict, p);}}else{repair(dict, key, value);}return errno;}// 修改字典元素errno_t repair(Dict* dict, const char* key, const char* value){Dict* r, * p; p = dict;_set_errno(0);if ((r = _findkey(dict, key)) != NULL){strcpy_s(r->data.key, N1, key);strcpy_s(r->data.value, N2, value);}else{append(dict, key, value);}return errno;}// 获取字典元素const char* get(Dict* dict, const char* key){Dict* p = dict->next;while (p != NULL){if (strcmp((p->data).key, key) == 0){return p->data.value;}p = p->next;}return "";}// 设置字典void set(Dict* dict, const char* key, const char* value){repair(dict, key, value);}// 判断key是否存在bool existkey(Dict* dict, const char* key){Dict* p = dict->next;bool result = 0;while (p != NULL){if (strcmp((p->data).key, key) == 0){result = 1; return p;}p = p->next;}return result;}// 显示所有记录void view(Dict* dict){int i = 0;Dict* p = dict->next;printf("{");while (p != NULL){printf("size:%d%s:%s,", dict->size, (p->data).key, (p->data).value);p = p->next;i++;}printf("}\n");}int main(int argc, char *argv[]){Dict* dict = NULL;dict = __init__(dict);// 追加键值对append(dict, "address", "192.168.1.1");append(dict, "username", "root");append(dict, "password", "1233");append(dict, "port", "22");// 替换预设值repair(dict, "password", "123456");set(dict, "password", "123456789");// 判断并输出if (existkey(dict, "address")){std::cout << "获取数据: " << get(dict, "address") << std::endl;std::cout << "获取数据: " << get(dict, "password") << std::endl;}// 清理记录clear(dict, "address");clear(dict, "username");clear(dict, "password");clear(dict, "port");__destroy__(dict);return 0;}

字符串URL编码与解码: 将一段URL字符串进行编码与解码的函数过程实现.

#include // 编码URLstd::string encode_url(const char* url, size_t url_length, bool space2plus){static char hex[] = "0123456789ABCDEF";std::string result(url_length * 3 + 1, '\0');int i = 0;while (*url != '\0'){char c = *url++;if (' ' == c){if (space2plus){result[i++] = '+';}else{// 新标准将空格替换为加号+result[i + 0] = '%';result[i + 1] = '2';result[i + 2] = '0';i += 3;}}else if ((c >= '0' && c <= '9') ||(c >= 'a' && c <= 'z') ||(c >= 'A' && c <= 'Z') ||(c == '-') || (c == '_') ||(c == '.') || (c == '~')){// RFC 3986标准定义的未保留字符 (2005年1月)result[i++] = c;}else{// 有符号的c值可能是负数result[i + 0] = '%';result[i + 1] = hex[static_cast<unsigned char>(c) / 16];result[i + 2] = hex[static_cast<unsigned char>(c) % 16];i += 3;}}result.resize(i);return result;}// 解码URLstd::string decode_url(const char* encoded_url, size_t encoded_url_length){std::string result(encoded_url_length + 1, '\0');int i = 0;while (*encoded_url != '\0'){char c = *encoded_url++;if (c == '+'){result[i++] = ' ';}else if (c != '%'){result[i++] = c;}else{if (!isxdigit(encoded_url[0]) ||!isxdigit(encoded_url[1])){result[i++] = '%';}else{char hex[3];hex[0] = encoded_url[0];hex[1] = encoded_url[1];hex[2] = '\0';char x = strtol(hex, NULL, 16);result[i++] = x;encoded_url += 2;}}}result.resize(i);return result;}int main(int argc, char* argv[]){const char* szUrl = "https://www.lyshark.com/index.php?uid=102";std::string encode = encode_url(szUrl, strlen(szUrl), false);std::cout << "编码后: " << encode << std::endl;std::string decode = decode_url(encode.c_str(), strlen(encode.c_str()));std::cout << "解码后: " << decode << std::endl;return 0;}

字符串编码互相转换: 在C++语言中通过多种方式实现wstring/wcharstring字符串之间的相互转换.

#include #include #include #include #pragma comment(lib, "comsuppw.lib")using namespace std;// 将string转换成wstringwstring string2wstring(string str){wstring result;//获取缓冲区大小,并申请空间,缓冲区大小按字符计算int len = MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), NULL, 0);TCHAR* buffer = new TCHAR[len + 1];// 多字节编码转换成宽字节编码MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), buffer, len);buffer[len] = '\0';// 删除缓冲区并返回值result.append(buffer);delete[] buffer;return result;}// 将wstring转换成stringstring wstring2string(wstring wstr){string result;//获取缓冲区大小,并申请空间,缓冲区大小事按字节计算的int len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), NULL, 0, NULL, NULL);char* buffer = new char[len + 1];//宽字节编码转换成多字节编码WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), buffer, len, NULL, NULL);buffer[len] = '\0';//删除缓冲区并返回值result.append(buffer);delete[] buffer;return result;}// 采用ATL封装_bstr_t => wstring 转stringstring ws2s(const wstring& ws){_bstr_t t = ws.c_str();char* pchar = (char*)t;string result = pchar;return result;}// 采用ATL封装_bstr_t => string 转wstringwstring s2ws(const string& s){_bstr_t t = s.c_str();wchar_t* pwchar = (wchar_t*)t;wstring result = pwchar;return result;}// 将 wchar => stringvoid WcharToString(std::string& szDst, wchar_t* wchar){wchar_t* wText = wchar;DWORD dwNum = WideCharToMultiByte(CP_OEMCP, NULL, wText, -1, NULL, 0, NULL, FALSE);char* psText;// psText 为 char* 的临时数组 作为赋值给std::string的中间变量psText = new char[dwNum];WideCharToMultiByte(CP_OEMCP, NULL, wText, -1, psText, dwNum, NULL, FALSE);szDst = psText;delete[]psText;}int main(int argc, char* argv[]){std::string stringA("hello lyshark");std::wstring wstringA(L"hello lyshark");// 使用原生API进行转换std::wcout << "string -> wstring: " << string2wstring(stringA) << std::endl;std::cout << "wstring -> string: " << wstring2string(wstringA) << std::endl;// 使用ATL进行转换std::wcout << "string -> wstring: " << s2ws(stringA) << std::endl;std::cout << "wstring -> string: " << ws2s(wstringA) << std::endl;// 使用C++标准库转换wstring_convert<codecvt<wchar_t, char, mbstate_t>> converter(new codecvt<wchar_t, char, mbstate_t>("CHS"));string narrowStr = converter.to_bytes(wstringA);wstring wstr = converter.from_bytes(narrowStr);std::cout << "wstring -> string: " << narrowStr << std::endl;wcout.imbue(locale("chs"));std::wcout << "string -> wstring: " << wstr << std::endl;// 将wchar转为stringWCHAR selfFile[MAX_PATH];//获取当前进程路径GetModuleFileName(NULL, selfFile, MAX_PATH);// 当前程序存放路径string Current_Path;WcharToString(Current_Path, selfFile);std::cout << "wchar -> string: " << Current_Path << std::endl;return 0;}

解析字符串字典: 与模拟Python字典不同,如下是通过C++直接实现了解析字符串格式的文本为字典,能够直接当字典解析.

#include #include #include // 切割字符串void SplitString(const std::string& s, std::vector<std::string>& vect, const std::string& c){std::string::size_type pos1, pos2;pos2 = s.find(c);pos1 = 0;while (std::string::npos != pos2){vect.push_back(s.substr(pos1, pos2 - pos1));pos1 = pos2 + c.size();pos2 = s.find(c, pos1);}if (pos1 != s.length())vect.push_back(s.substr(pos1));}// 删除左右两边空格void Del_Trim(std::string& s){if (s.empty()){return;}s.erase(0, s.find_first_not_of(" "));s.erase(s.find_last_not_of(" ") + 1);}// 删除所有空格void Del_Space(std::string& res){int r = res.find('\r\n');while (r != std::string::npos){if (r != std::string::npos){res.replace(r, 1, "");r = res.find('\r\n');}}res.erase(std::remove_if(res.begin(), res.end(), std::isspace), res.end());}// 删除字符串中的指定符号void Del_Char(std::string& res ,char ch){int r = res.find(ch);while (r != std::string::npos){if (r != std::string::npos){res.replace(r, 1, "");r = res.find(ch);}}res.erase(std::remove_if(res.begin(), res.end(), std::isspace), res.end());}// 传入key返回valuestd::string get_value(std::string szDict, std::string key){// 去掉空格Del_Space(szDict);// 去掉特殊字符Del_Char(szDict, '\'');Del_Char(szDict, '{');Del_Char(szDict, '}');// 先使用逗号切割第一次std::vector<std::string> one_split;SplitString(szDict, one_split, ",");for (int x = 0; x < one_split.size(); x++){// 循环切割第二次std::vector<std::string> two_split;SplitString(one_split[x], two_split, ":");// std::cout << "key = " << two_split[0] << " value = " << two_split[1] << std::endl;// 寻找key所对应的valueif (strcmp(two_split[0].c_str(), key.c_str()) == 0){return two_split[1];}}return "None";}int main(int argc, char* argv[]){std::string szDict = "{'address' : '192.168.1.1' , 'username' : 'root' , 'password' : '123123' , 'port': '22'}";std::string address_value = get_value(szDict, "address");std::cout << "返回地址: " << address_value << std::endl;std::string username_value = get_value(szDict, "username");std::cout << "返回用户: " << username_value << std::endl;return 0;}

字符串正反向对比与截取: 实现了字符串反向对比以及截取指定位置字符串对比功能.

#include #include // 将字符串逆序char* reverse(char str[]){int n = strlen(str);int i;char temp;for (i = 0; i < (n / 2); i++){temp = str[i];str[i] = str[n - i - 1];str[n - i - 1] = temp;}return str;}// 从字符串src中的count位置出开始复制,复制长度为lenbool strnrcpy(char* src, char &dst, int count, int len){int str = strlen(src);std::cout << str << std::endl;for (int x = 0; x < strlen(src); x++){if (x >= count){strncpy(&dst , src + count + 1, len + 1);break;}}return true;}int main(int argc, char *argv[]){char szBuf[1024] = "Internet Explorer";char szRef[1024] = { 0 };// 反向对比字符串if (strcmp(reverse(szBuf), "rerolpxE tenretnI") == 0){std::cout << "先逆序排列,在对比" << std::endl;}// 字符串提取位置并对比reverse(szBuf);bool ref = strnrcpy(szBuf, *szRef, 8, 8);if (ref == true){std::cout << "提取字符串: " << szRef << std::endl;if (strcmp(szRef, "Explorer") == 0){std::cout << "数据一致" << std::endl;}}return 0;}

6.1.2 复制与剪切函数

memset 内存填充: 设置某个范围内每字节的值,通常用来清空结构体或者清空某块内存。

#include #include // 标准库void* memset(char* s, int c, size_t n){const unsigned char uc = c;char* su;for (su = s; 0 < n; ++su, --n)*su = uc;return (s);}int main(int argc, char* argv[]){// 获取10字节的内存char* p = (char*)malloc(sizeof(char) * 10);// 将该10字节内存全部初始化为0memset(p, 0, sizeof(char) * 10);return 0;}

memcpy 内存拷贝: 函数memcpy从s2指向的对象中复制n个字符到s1指定的对象中。

#include #include // 标准库void* memcpy(char* s1, const char* s2, size_t n){char* su1;const char* su2;for (su1 = s1, su2 = s2; 0 < n; ++su1, ++su2, --n){*su1 = *su2;}return s1;}// 自实现void* _memcpy(char* s1, char* s2, size_t n){char* start, * src;start = s1;src = s2;while (n > 0 && (*start++ = *src++) != '\0')n--;while (n-- > 0)*start++ = '\0';*start = '\0';return s1;}int main(int argc, char const* argv[]){char text[20] = {0};std::cout << "标准库: " << text << " 地址: " << memcpy(text, "hello lyshark", 13) << std::endl;std::cout << "自实现: " << text << " 地址: " << _memcpy(text, (char *)"hello lyshark", 13) << std::endl;return 0;}

memmove 内存移动: 函数memmove从s2指向的对象中复制n个字符串到s1指向的对象中。

#include #include // 标准库void* memmove(char* s1, const char* s2, size_t n){char* sc1;const char* sc2;sc1 = s1;sc2 = s2;// 如果 sc1 的地址比 sc2 要低,并且两者相处不足 n 字节if (sc2 < sc1 && sc1 < sc2 + n){// 逆向复制for (sc1 += n, sc2 += n; 0 < n; --n){*--sc1 = *--sc2;}}else{// 正向复制for (; 0 < n; --n){*sc1++ = *sc2++;}}return s1;}// 自实现void* _memmove(char* s1, const char* s2, size_t n){char* su1;const char* su2;int i;if (s1 < s2 && s2 - s1 < n){// 加了 n 忘记减一了for (su1 = s1 + n, su2 = s2 + n; n > 0; --n, --su1, --su2){*su1 = *su2;}}else{// i 多余了for (i = 0, su1 = s1, su2 = s2; i < n; ++i, ++su1, ++su2){*su1 = *su2;}}return s1;}int main(int argc, char const* argv[]){char text[20] = {0};std::cout << "标准库: " << text << " 地址: " << memmove(text, "hello lyshark", 13) << std::endl;std::cout << "自实现: " << text << " 地址: " << _memmove(text, (char *)"hello lyshark", 13) << std::endl;return 0;}

strcpy 字符串拷贝: 把s2指向的串(包括终止的空字符)复制到s1指向的数组中。

#include // 标准库char* strcpy(char* s1, const char* s2){char* s = s1;for (s = s1; (*s++ = *s2++) != '\0'; );return s1;}// 自实现char* _strcpy(char* s1, const char* s2){char* start = s1;while (*s1++ = *s2++);return start;}int main(int argc, char const* argv[]){char text[20] = {0};strcpy(text, "hello lyshark");return 0;}

strncpy 字符串前N字节拷贝: 把s2指向的串(包括终止的空字符)复制到s1指向的数组中。

#include // 标准库char* (strncpy)(char* s1, const char* s2, size_t n){char* s;// 当n不为0 且s2为拷贝完时,复制字符过去for (s = s1; 0 < n && *s2 != '\0'; ++s)*s++ = *s2++;// 若n有多出,则补零for (; 0 < n; --n)*s++ = '\0';return s1;}// 自实现char* _strncpy(char* s1, const char* s2, size_t n){char* start = s1, count = 0;while ((count < n) && (*s1 = *s2)){count++, s1++, s2++;// printf("第%d个 已拷贝n", count);}while (count++ < n){*s1++ = '\0';// printf("第%d个 已补零n", count);}return start;}int main(int argc, char const* argv[]){char text[20] = {0};strncpy(text, "hello lyshark",5);_strncpy(text, "hello lyshark", 6);return 0;}

strcat 字符串连接: 函数strcat把s2指向的串(包括终止的空字符)的副本添加到s1指向的串的末尾。

#include // 标准库char* strcat(char* s1, const char* s2){char* s;// 指针移动到s1的结尾for (s = s1; *s != '\0'; ++s);// 如果s2未结尾则拷贝for (; (*s = *s2) != '\0'; ++s, ++s2);return (s1);}// 自实现char* _strcat(char* s1, const char* s2){char* start = s1;while (*s1)s1++;while (*s1++ = *s2++);return start;}int main(int argc, char const* argv[]){char text[20] = "hello ";printf("%s \n", _strcat(text, "lyshark"));return 0;}

strncat 字符串连接前N个字节: 函数strncat从s2指向的数组中将最多n个字符(空字符及其后面的字符不添加)添加到s1指向的串的末尾。

#include // 标准库char* strncat(char* s1, const char* s2, size_t n){char* s;// 指针移动到s1的结尾for (s = s1; *s != '\0'; ++s);// 如果s2未结尾则拷贝for (; 0 < n && *s2 != '\0'; --n)*s++ = *s2++;// 字符串s1结尾补'\0'*s = '\0';return (s1);}// 自实现char* _strncat(char* s1, const char* s2, size_t n){char* start = s1;while (*s1)s1++;while ((0 < n--) && (*s1++ = *s2++)){;// printf("第%d个 已赋值n", n);}while (0 < n--){*s1++ = '\0';// printf("第%d个 已补零n", n);}return start;}int main(int argc, char const* argv[]){char text[20] = "hello ";printf("%s \n", strncat(text, "lyshark", 5));printf("%s \n", _strncat(text, "lyshark",8));return 0;}

6.1.3 字符串比较函数

strlen 字符串取长度: 字符串长度获取函数,用于获取一段以0结尾的字符串长度。

#include // 标准库int strlen(const char* s){const char* sc;for (sc = s; *sc != '\0'; ++sc);return (sc - s);}// 自实现int _strlen(const char* dest){const char* start = dest;while (*dest)dest++;return (dest - start);}int main(int argc, char const* argv[]){printf("%d", _strlen("hello lyshark"));return 0;}

strcmp 字符串比较: 字符串比较函数,用于比较两个字符串的区别。

#include // 标准库int strcmp(const char* s1, const char* s2){for (; *s1 == *s2; ++s1, ++s2)if (*s1 == '\0')return (0);return ((*(unsigned char*)s1 < *(unsigned char*)s2) ? -1 : +1);}// 自实现int _strcmp(const char* dest, const char* src){int res = 0;while (res == 0 && *src != '\0')res = *dest++ - *src++;return res;}int main(int argc, char const* argv[]){char text[20] = "hello ";if (_strcmp(text, "hello ") == 0){printf("相等");}return 0;}

strncmp 比较前N个字符: 比较两个字符串的前n个字符。

#include // 标准库int strncmp(const char* s1, const char* s2, size_t n){for (; 0 < n; ++s1, ++s2, --n)if (*s1 != *s2)return ((*(unsigned char*)s1 < *(unsigned char*)s2) ? -1 : +1);else if (*s1 == '\0')return 0;return 0;}// 自实现int _strncmp(const char* s1, const char* s2, size_t n){const char* dest = s1, * src = s2;while (n-- > 0 && *dest != '\0')if (*dest++ - *src++)return *dest - *src;return 0;}int main(int argc, char const* argv[]){char text[20] = "hello ";if (_strncmp(text, "he", 2) == 0){printf("相等");}return 0;}

memcmp 内存字节比较: 该函数与strcmp类似,区别在于memcmp不会检查字符串是否到结束。

#include // 标准库int memcmp(const char* s1, const char* s2, size_t n){const char* su1, * su2;for (su1 = s1, su2 = su2; 0 < n; ++su1, ++su2, --n)if (*su1 != *su2)return ((*su1 < *su2) ? -1 : +1);return 0;}// 自实现int _memcmp(const char* s1, const char* s2, size_t n){const char* dest = s1, * src = s2;while (n-- > 0)if (*dest++ - *src++)return *dest - *src;return 0;}int main(int argc, char const* argv[]){char text[20] = "hello ";if (_memcmp(text, "he", 2) == 0){printf("相等");}return 0;}

strcoll/strxfrm 中文字符串比较: 该函数主要实现中文字符串的比较。

locale.h本地库有关的字符串比较函数,在开始比较之前会按照特定的方式转换字符串然后在进行比较。

#include #include #include #define ST_CH 0x00ff#define ST_STATE0x0f00#define ST_STOFF8#define ST_FOLD 0x8000#define ST_INPUT0x4000#define ST_OUTPUT 0x2000#define ST_ROTATE 0x1000#define _NSTATE 16/* 类型定义 */typedef struct {const unsigned short* _Tab[_NSTATE];} _Statab;/* 声明*/extern _Statab _Costate, _Mbstate, _Wcstate;/* type definnitions 类型定义 */typedef struct {unsigned char _State;unsigned short _Wchar;} _Cosave;/* declarations 声明 */size_t _Strxfrm(char*, const unsigned char**, size_t, _Cosave*);/* 设置默认为 0 的本地配置项 */_Statab _Costate, _Mbstate, _Wcstate;// _Cosave 存储状态信息size_t _Strxfrm(char* sout, const unsigned char** psin,size_t size, _Cosave* ps){// 翻译字符串到可校对的格式char state = ps->_State;int leave = 0;int limit = 0;int nout = 0;const unsigned char* sin = *psin;// 宽字节字符累加器unsigned short wc = ps->_Wchar;for (; ; ){// 执行状态转换unsigned short code;const unsigned short* stab;if (_NSTATE <= state|| (stab = _Costate._Tab[state]) == NULL|| (_NSTATE * UCHAR_MAX) <= ++limit|| (code = stab[*sin] == 0))break;state = (code & ST_STATE) >> ST_STOFF;if (code & ST_FOLD)wc = wc & ~UCHAR_MAX | code & ST_CH;if (code & ST_ROTATE)wc = wc >> CHAR_BIT & UCHAR_MAX | wc << CHAR_BIT;if (code & ST_OUTPUT && ((sout[nout++]= code & ST_CH ? code : wc) == '\0'|| size <= nout))leave = 1;if (code & ST_INPUT)if (*sin != '\0')++sin, limit = 0;elseleave = 1;if (leave){// 现在返回*psin = sin;ps->_State = state;ps->_Wchar = wc;return nout;}}// 错误返回sout[nout++] = '\0';*psin = sin;ps->_State = _NSTATE;return nout;}

定义好以上转换过程,就可以进行比较了,函数_strcoll()主要用于比较完整中文字符串,而_strxfrm()则用于比较指定的前几个中文字符。

typedef struct{char buf[32];const unsigned char* s1, * s2, * sout;_Cosave state;} Sctl;static size_t getxfrm(Sctl* p){size_t i;do{p->sout = (const unsigned char*)p->buf;i = _Strxfrm(p->buf, &p->s1, sizeof(p->buf), &p->state);if (0 < i && p->buf[i - 1] == '\0')return (i - 1);else if (*p->s1 == '\0')p->s1 = p->s2;} while (i == 0);return i;}// 比较全部中文字符串int _strcoll(const char* s1, const char* s2){size_t n1, n2;Sctl st1, st2;static const _Cosave initial = { 0 };st1.s1 = (const unsigned char*)s1;st2.s2 = (const unsigned char*)s1;st1.state = initial;st2.s1 = (const unsigned char*)s2;st2.s2 = (const unsigned char*)s2;st2.state = initial;for (n1 = n2 = 0; ; ){int ans;size_t n;if (n1 == 0)n1 = getxfrm(&st1);if (n2 == 0)n2 = getxfrm(&st2);n = n1 < n2 ? n1 : n2;if (n == 0)return (n1 == n2 ? 0 : 0 < n2 ? -1 : +1);else if ((ans = memcmp(st1.sout, st2.sout, n)) != 0)return ans;st1.sout += n, n1 -= n;st2.sout += n, n2 -= n;}}// 指定比较行size_t _strxfrm(char* s1, const char* s2, size_t n){size_t nx = 0;const unsigned char* s = (const unsigned char*)s2;_Cosave state = { 0 };while (nx < n){// 转化 并 传递size_t i = _Strxfrm(s1, &s, n - nx, &state);s1 += i, nx += i;if (0 < i && s1[-1] == '\0')return nx - 1;else if (*s == '\0')s = (const unsigned char*)s2;}for (; ; ){char buf[32];size_t i = _Strxfrm(buf, &s, sizeof(buf), &state);nx += i;if (0 < i && buf[i - 1] == '\0')return nx - 1;else if (*s == '\0')s = (const unsigned char*)s2;}}int main(int argc, char *argv[]){char hi[] = "中文";if (_strcoll(hi, "中文") == 0){printf("相等");}if (_strxfrm(hi, "中", 1) == 0){printf("相等");}return 0;}

6.1.4 字符串查找函数

memchr 内存中查找: 内存中查找,参数void *适合各种数据类型,不过只能查找一个字节。

#include #include // 标准库void *memchr(const void *s, int c, size_t n){const unsigned char uc = c;const unsigned char *su; for (su = s; 0 < n; ++su, --n)if (*su == uc)return ((void *)su);return (NULL);}// 自实现void *_memchr(const void *s, int c, size_t n){const unsigned char *pstr = s;const unsigned char search = (unsigned char)c; while(n-- > 0){if (*pstr == search){return (void *)pstr;}pstr++;} return NULL;} int main(int argc, char *argv[]){char *p;p = _memchr("hello lyshark", 'w', 8);printf("%sn", p);return 0;}

strchr 字符串中查找: 字符串中查找字符,并返回这个字符第一次出现的地址。

#include #include // 标准库char *strchr(const char *s, int c){const char ch = c; for (; *s != '\0'; ++s)if (*s == '\0')return NULL;return ((char *)s);}// 自实现char *_strchr(const char *s, int c){const unsigned char *pstr = s;const unsigned char search = (unsigned char)c; while(*pstr != '\0'){if (*pstr == search){return (char *)pstr;}pstr++;}return NULL;}int main(int argc, char *argv[]){char *p;p = _strchr("hello lyshark", 'o');printf("%s", p);return 0;}

strrchr 字符串中反向查找: 字符串反向查找字符,返回这个字符最后一次出现的位置。

#include #include // 标准库char *strrchr(const char *s, int c){const char ch = c;const char *sc; for (sc = NULL; ; ++s){if (*s == ch)sc = s;if (*s == '\0')return ((char *)sc);}}// 自实现char *_strrchr(const char *s, int c){const unsigned char *pstr = NULL, search = (unsigned char)c; do{if (*s == search){pstr = s;}} while (*s++); return (char *)pstr;}int main(int argc, char *argv[]){char *p;p = strrchr("hello lyshark", 'o');printf("%s", p);return 0;}

strstr 字符中查找字符串: 字符串中查找字符串,如果能找到则返回其地址找不到则返回NULL。

#include #include // 标准库char *strstr(const char *s1, const char *s2){if(*s2 == '\0')return ((char *)s1);for( ; (s1 = strchr(s1, *s2)) != NULL; ++s1){const char *sc1, *sc2; for(sc1 = s1, sc2 = s2; ; )if(*++sc2 == '\0')return ((char *)s1);else if(*++sc1 != *sc2)break;}return NULL;}// 自实现char *_strstr(const char *s1, const char *s2){while ( (s1 = strchr(s1, *s2)) != NULL )if(strcmp(s1, s2) == 0)return (char *)s1;elses1++;return NULL;}int main(int argc, char *argv[]){printf("%s", _strstr("that this think", "think"));return 0;}

strtok 根据标识查找字符串: 通过标识来查找字符串,需要注意的是这个会修改原来字符串的值。

#include #include char * strtok(char *s1, const char *s2){char *sbegin, *send;static char *ssave = ""; sbegin = s1 ? s1 : ssave;// printf("1.sbegin: %sn", sbegin);// printf("2.strspn(sbegin, s2): %dn", strspn(sbegin, s2));sbegin += strspn(sbegin, s2);if (*sbegin == '\0'){ssave = "";return NULL;} // printf("3.sbegin: %sn", sbegin);send = sbegin + strcspn(sbegin, s2);// printf("4.sbegin: %sn", sbegin);// printf("5.send: %sn", send); if (*send != '\0')*send++ = '\0'; ssave = send;// printf("6.send: %sn", send);return (sbegin);} int main(int argc, char *argv[]){char input[] = "program,hello,world";char *p; /* 截取到第一个标识符之前 */p = strtok(input, "e");if(p){printf("%sn", p);}/* 截取第一个标识符之后一段 */p = strtok(NULL, "e");if(p){printf("%sn", p);} // 源字符串被截断printf("最后input : %s", input);return 0;}

strspn 范围之内查找: 字符串范围查找,在s1中找s2,从s1的开头依次与s2比较,返回第一个与s2不同的字符下标。

#include #include  // 函数说明 strspn 返回字符串中第一个不在指定字符串中出现的字符下标size_t _strspn(const char *s1,const char *s2){const char *sc1 = s1, *sc2 = s2; for(sc1 = s1, sc2 = s2; *sc1 != '\0'; ++sc1, ++sc2)if (*sc2 == '\0')return (sc1 - s1);else if (*sc1 == *sc2)continue;elsebreak;return sc1 - s1;}size_t strspn(const char *s1,const char *s2){const char *sc1, *sc2; printf("sc2: [%s] ", s2); for(sc1 = s1; *sc1 != '\0'; ++sc1)for (sc2 = s2; ; ++sc2)if (*sc2 == '\0')return (sc1 - s1);else if (*sc1 == *sc2)break;return (sc1 - s1);}int main(int argc, char const *argv[]){char *str = "what do you think about this this program? 1";printf("%dn", _strspn(str,"w"));printf("%dn", _strspn(str,"what"));printf("%dn", _strspn(str,"what "));printf("%dn", _strspn(str,"what d"));printf("%dn", _strspn(str,"what do"));printf("%dn", _strspn(str,"what do "));printf("%dn", _strspn(str,"what do y"));printf("%dn", _strspn(str,"what do yo"));printf("%dn", _strspn(str,"what do you"));printf("%dn", _strspn(str,"you"));printf("%dn", _strspn(str,"1234567890"));return 0;}

strcspn 范围之外查找: 在字符串s1中搜寻与s2中字符的第一个相同字符,包括结束符NULL,返回这个字符在S1中第一次出现的位置。

#include #include // 标准库size_t strcspn(const char *s1,const char *s2){const char *sc1, *sc2; for (sc1 = s1; *sc1 != '\0'; ++sc1)for(sc2 = s2; *sc2 != '\0'; ++sc2)if (*sc1 == *sc2)return (sc1 - s1);// 返回NULL,即字符串结束return (sc1 - s1);}int main(int argc, char *argv[]){char *str = "Linux was first developed for 386/486-based pcs. ";printf("字符串长度为 %dn", strlen(str));printf("%dn", strcspn(str, " "));printf("%dn", strcspn(str, "/-"));printf("%dn", strcspn(str, "1234567890"));printf("%dn", strcspn(str, ""));return 0;}

strpbrk可以理解为找到目标(string)中的字符后中断(break)并返回其地址(pointer),其功能与strcspn相同,区别只是strpbrk返回的是地址。

#include #include  /*依次检验字符串s1中的字符,当被检验字符在字符串s2中也包含时则停止检验,并返回该字符地址,空字符NULL不包括在内。*/// 标准库char * strpbrk(const char * s1,const char * s2){const char *sc1, *sc2; for(sc1 = s1; *sc1 !='\0'; ++sc1)for(sc2 = s2; *sc2 !='\0'; ++sc2)if(*sc1 == *sc2)return ((char *)sc1);return NULL;} int main(int argc, char *argv[]){char *s1="Welcome To Beijing";char *s2="BIT";char *p; p = strpbrk(s1,s2);if(p)printf("%sn",p);elseprintf("Not Found!n"); p = strpbrk(s1, "Daj"); if(p)printf("%s",p);elseprintf("Not Found!n"); return 0;}

本文作者: 王瑞
本文链接: https://www.lyshark.com/post/feee755.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!