字符串处理
char* 窄字符
#include <Windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
//变量c分配了1字节的存储空间,并使用16进制数 Ox41来初始化他(字符A的ASCII置为Ox41)
char c = 'A';
//指针变量pStr 需要4字节的存储空间,指针变量pStr 指向的字符串需要7字节的存储空间。
const char* pStr = "Hello!";
//字符数组 szStr 同样需要7字节的存储空间
char szStr[] = "Hello!";
return 0;
}
w_char* 宽字符
Unicode(一般指的是UTF-16),统一用2个字节来表达一个字符。
#include <Windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
//大写字母L表明右边的字符使用宽字符进行存储
//变量wc分配了2个字节的存储空间,并使用16进制数Ox0041来初始化他
wchar_t wc = L'A';
//指针变量pwStr 需要4字节的存储空间. 指针变量pwStr 指向的字符串需要14字节的存储空间。
const wchar_t* pwStr = L"Hello";
//字符数组szwStr 同样也需要14字节的存储空间。
wchar_t szwStr[] = L"Hello";
return 0;
}
利用sizeof
操作符,去查下面变量占用内存多少字节。
char ch = 'A'; //1
wchar_t wch = L'A'; //2
char str[] = "C语言"; //6
wchar_t wstr[] = L"C语言"; //8
printf("ch=%d,wch = %d str = %d wstr = %d",
sizeof ch,
sizeof wch,
sizeof str,
sizeof wstr);
为啥是1,2,6,8.能理解就说明你已经知道的多字节字符集存储字符和Unicode字符集存储字符的区别了。
TCHAR通用数据类型
WINDOWS在winnt.h
头文件中,定义了自己的字符和宽字符数据类型。
typedef char CHAR; //字符
#ifndef _MAC
typedef wchar_t WCHAR; //宽字符
#else
typedef unsigned short WCHAR; // Macintosh编译器 没有定义wchar_t数据类型,宽字符会被定义为16位整数值
#endif
winnet.h头文件还有如下定义:
//
// Neutral ANSI/UNICODE types and macros
//
#ifdef UNICODE // r_winnt
#ifndef _TCHAR_DEFINED
typedef WCHAR TCHAR, *PTCHAR;
typedef WCHAR TBYTE , *PTBYTE ;
#define _TCHAR_DEFINED
#endif /* !_TCHAR_DEFINED */
typedef LPWCH LPTCH, PTCH;
typedef LPCWCH LPCTCH, PCTCH;
typedef LPWSTR PTSTR, LPTSTR;
typedef LPCWSTR PCTSTR, LPCTSTR;
typedef LPUWSTR PUTSTR, LPUTSTR;
typedef LPCUWSTR PCUTSTR, LPCUTSTR;
typedef LPWSTR LP;
typedef PZZWSTR PZZTSTR;
typedef PCZZWSTR PCZZTSTR;
typedef PUZZWSTR PUZZTSTR;
typedef PCUZZWSTR PCUZZTSTR;
typedef PZPWSTR PZPTSTR;
typedef PNZWCH PNZTCH;
typedef PCNZWCH PCNZTCH;
typedef PUNZWCH PUNZTCH;
typedef PCUNZWCH PCUNZTCH;
#define __TEXT(quote) L##quote // r_winnt
#else /* UNICODE */ // r_winnt
#ifndef _TCHAR_DEFINED
typedef char TCHAR, *PTCHAR;
typedef unsigned char TBYTE , *PTBYTE ;
#define _TCHAR_DEFINED
#endif /* !_TCHAR_DEFINED */
typedef LPCH LPTCH, PTCH;
typedef LPCCH LPCTCH, PCTCH;
typedef LPSTR PTSTR, LPTSTR, PUTSTR, LPUTSTR;
typedef LPCSTR PCTSTR, LPCTSTR, PCUTSTR, LPCUTSTR;
typedef PZZSTR PZZTSTR, PUZZTSTR;
typedef PCZZSTR PCZZTSTR, PCUZZTSTR;
typedef PZPSTR PZPTSTR;
typedef PNZCH PNZTCH, PUNZTCH;
typedef PCNZCH PCNZTCH, PCUNZTCH;
#define __TEXT(quote) quote // r_winnt
#endif /* UNICODE */
这里UNICODE
宏存在不存在决定了带T通用类型,是用的具体什么类型。一般用VS创建工程,默认使用的是Unicode字符集,我们可以在C/C++ 命令行
中可以看到UNICODE
和_UNICODE
宏被定义了。如果我们修改为多字节字符集,则可以看不到UNICODE
和_UNICODE
宏被定义了。
总的来说,WINDOW程序设计,要么这个UNICODE
_UNICODE
被定义,要么都不被定义。根据此宏,TCHAR被解释为CHAR(char
) 或者 WCHAR(wchar_t
)数据类型。
#ifdef UNICODE
#define __TEXT(quote) L##quote
#else /* UNICODE */
#define __TEXT(quote) quote
__TEXT()
##
被称为令牌粘贴, 即当quote="Hello"
时 L##quote
就是 L"Hello"
.
这个宏的目的就是说,如果.cpp
文件中有以下定义:
TCHAR szBuf[] = TEXT("C语言");
如果这个项目是 Unicode字符集,则上面的定义将被解释为:
WCHAR szBuf[] = L"C语言";
又如果说这个项目是多字节字符集,则上面的定义将被解释为:
CHAR szBuf[] = "C语言";
常用字符串处理函数
查字符串长度
size_t __cdecl strlen(_In_z_ char const* _Str ); //char 类型字符串指针
size_t __cdecl wcslen( _In_z_ wchar_t const* _String ); //wchar类型字符串 指针
size_t
在vcruntime.h
头文件中定义如下:
// Definitions of common types
#ifdef _WIN64 // 如果编译为64位程序,那么 size_t 表示64位无符号整型
typedef unsigned __int64 size_t;
typedef __int64 ptrdiff_t;
typedef __int64 intptr_t;
#else
typedef unsigned int size_t; //反之,如果编译为32位程序,则表示32位无符号整型
typedef int ptrdiff_t;
typedef int intptr_t;
#endif
查字符串中首次出现的字符
#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
int main()
{
TCHAR szStr[] = TEXT("WindowAPI是最为强大的编程语言!");
LPTSTR lp = _tcschr(szStr,_T('最')); //查不到字符返回NULL,查到返回指向这个字符的地址
setlocale(LC_ALL, "chs"); //用_tprintf函数输出中文字符的时候,需要调用本函数设置区域。
_tprintf(_T("szStr的地址 %p lp的地址 %p\n"), szStr, lp);
// szStr的地址 0000006A4BBDF6C8 lp的地址 0000006A4BBDF6DC
_tprintf(_T("%s"), lp);//最为强大的编程语言!
return 0;
}
查子串出现的位置
如果说strSearch是str的字串,则返回strSearch在str中首次出现的地址,如果strSearch不是str的子串,就返回NULL.
char* __CRTDECL strstr(_In_z_ char* const str, _In_z_ char const* const strSearch)
wchar_t* __CRTDECL wcsstr(_In_z_ wchar_t* str, _In_z_ wchar_t const* strSearch)
#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
int main()
{
TCHAR szStr[] = TEXT("Hello,Windows,Windows API program simple and Powerful!");
TCHAR szStrSearch[] = TEXT("Windows");
_tprintf(TEXT("%s\n"), _tcsstr(szStr, szStrSearch));
//Windows,Windows API program simple and Powerful!
return 0;
}
从一个字符串中查找另一个字符串中的任何字符
char* __CRTDECL strpbrk(_In_z_ char* const str, _In_z_ char const* const _Control)
wchar_t* __CRTDECL wcspbrk(_In_z_ wchar_t* str, _In_z_ wchar_t const* _Control)
函数在源字符串str中找出最先含有搜索字符串strCharSet中任一字符的位置并返回,如果找不到则返回NULL.
#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
int main()
{
TCHAR szStr[] = TEXT("the 3 men and 2 boys ate 5 pigs");
TCHAR szStrCharSet[] = TEXT("0123456789");
LPTSTR lpSearch = NULL;
_tprintf(TEXT("1:%s\n"), szStr);
lpSearch = _tcspbrk(szStr, szStrCharSet);
_tprintf(TEXT("2:%s\n"), lpSearch);
lpSearch++;
lpSearch = _tcspbrk(lpSearch, szStrCharSet);
_tprintf(TEXT("3:%s\n"), lpSearch);
lpSearch++;
lpSearch = _tcspbrk(lpSearch, szStrCharSet);
_tprintf(_T("4:%s\n"), lpSearch);
//1:the 3 men and 2 boys ate 5 pigs
//2:3 men and 2 boys ate 5 pigs
//3:2 boys ate 5 pigs
//4:5 pigs
return 0;
}
转换字符串中的字符大小写
//将字符串转换为大写
_ACRTIMP errno_t __cdecl _wcsupr_s(
_Inout_updates_z_(_Size) wchar_t* str,
_In_ size_t _Size //字符个数
);
//把字符串转为小写
_Check_return_wat_ _ACRTIMP errno_t __cdecl _wcslwr_s(
_Inout_updates_z_(_SizeInWords) wchar_t* str,
_In_ size_t _SizeInWords //字符个数
);
//将字符转为小写
wint_t __cdecl towlower(_In_ wint_t _C);
//将字符转为大写
wint_t __cdecl towupper(_In_ wint_t _C);
#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
int main()
{
TCHAR szStr[] = _T("windows是一种强大的编程语言");
setlocale(LC_ALL, "chs");
_tcsupr_s(szStr, _tcslen(szStr) + 1); //将字符串中的小写字符变成大写字符
_tprintf(_T("%s\n"), szStr);
_tcslwr_s(szStr, _tcslen(szStr) + 1); //将字符串中的大写字符变成小写字符
_tprintf(_T("%s\n"), szStr);
//输出结果:
//WINDOWS是一种强大的编程语言
//windows是一种强大的编程语言
return 0;
}
#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
int main()
{
TCHAR szStr[] = _T("Hello,Windows,Windows API program simple and 强大!");
//把每一个字符转为小写
int count = _tcslen(szStr);
for (size_t i = 0; i < count; i++)
{
szStr[i] = _totlower(szStr[i]);
}
setlocale(LC_ALL, "chs");
_tprintf(_T("%s\n"), szStr);
//将字符串转为大写
for (size_t i = 0; i < count; i++)
{
szStr[i] = _totupper(szStr[i]);
}
_tprintf(_T("%s\n"), szStr);
return 0;
}
字符串拼接
_ACRTIMP errno_t __cdecl strcat_s(
_Inout_updates_z_(_SizeInBytes) char* _Destination,
_In_ rsize_t _SizeInBytes, //目标字符串缓冲区大小,字节单位
_In_z_ char const* _Source
);
_ACRTIMP errno_t __cdecl wcscat_s(
_Inout_updates_z_(_SizeInWords) wchar_t* _Destination,
_In_ rsize_t _SizeInWords,//目标缓存区大小,字符单位
_In_z_ wchar_t const* _Source
);
#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
int main()
{
TCHAR szStrDest[64] = TEXT("WindowsAPI");
TCHAR szStrSour[] = TEXT("是一种强大的编程语言!");
_tcscat_s(szStrDest, _countof(szStrDest), szStrSour); //注意,这是Uncoide字符集,使用的是wcscat_s,第二个参数注入字符个数。用_countof求算,得64个字符空间。
//如果用sizeof 则会得到128个字节。
//如果是多字节字符集得化,_countof求算也是64个字符空间,而sizeof 求算 会得到64字节空间。
//所以用_countof 可以兼容两个字符集,而sizeof 不行!
setlocale(LC_ALL, "chs");
_tprintf(TEXT("%s\n"), szStrDest);
}
建议直接用::StringCchCat()
替代使用 _tcscat_s()
#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
#include<strsafe.h>
int main()
{
TCHAR szStrDest[64] = TEXT("WindowsAPI");
TCHAR szStrSour[] = TEXT("是一种强大的编程语言!");
::StringCchCat(szStrDest, _countof(szStrDest), szStrSour);
setlocale(LC_ALL, "chs");
_tprintf(TEXT("%s\n"), szStrDest);
}
字符串复制
_ACRTIMP errno_t __cdecl strcpy_s(
_Out_writes_z_(_SizeInBytes) char* _Destination,
_In_ rsize_t _SizeInBytes,//目标缓冲区的大小,字节单位
_In_z_ char const* _Source
);
_ACRTIMP errno_t __cdecl wcscpy_s(
_Out_writes_z_(_SizeInWords) wchar_t* _Destination,
_In_ rsize_t _SizeInWords,//目标缓冲区的大熊啊,字符单位。
_In_z_ wchar_t const* _Source
);
#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
int main()
{
TCHAR szStrDest[64];
TCHAR szStrSour[] = _T("WindowsAPI是一种强大的编程语言!");
_tcscpy_s(szStrDest, _countof(szStrDest), szStrSour);
setlocale(LC_ALL, "chs");
_tprintf(_T("%s\n"), szStrDest);//WindowsAPI是一种强大的编程语言!
}
建议直接用::StringCchCopy()
替代使用_tcscpy_s()
.
#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
#include<strsafe.h>
int main()
{
TCHAR szStrDest[64];
TCHAR szStrSour[] = _T("WindowsAPI是一种强大的编程语言!");
::StringCchCopy(szStrDest, _countof(szStrDest), szStrSour);
setlocale(LC_ALL, "chs");
_tprintf(_T("%s\n"), szStrDest);//WindowsAPI是一种强大的编程语言!
}
字符串比较
比的是每一个字符的ASCII码,两个字符串相等返回0.
int __cdecl strcmp(
_In_z_ char const* _Str1,
_In_z_ char const* _Str2
);
_ACRTIMP int __cdecl wcscmp(
_In_z_ wchar_t const* _String1,
_In_z_ wchar_t const* _String2
);
#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
#include<strsafe.h>
int main()
{
TCHAR szStr1[] = TEXT("ABCDE"); //E的ASCII 为Ox45
TCHAR szStr2[] = TEXT("ABCDe"); //e的ASCII 为Ox65
int n = _tcscmp(szStr1, szStr2);
setlocale(LC_ALL, "chs");
if (n > 0)
{
_tprintf(_T("szStr1 大于 szStr2\n"));
}
else if (n == 0)
{
_tprintf(_T("szStr1 等于 szStr2\n"));
}
else // n < 0
{
_tprintf(_T("szStr1 小于 szStr2\n"));
}
//szStr1 小于 szStr2
//忽略大小写比较
int n1 = _tcsicmp(szStr1, szStr2);
if (n1 > 0)
{
_tprintf(_T("szStr1 大于 szStr2\n"));
}
else if (n1 == 0)
{
_tprintf(_T("szStr1 等于 szStr2\n"));
}
else // n < 0
{
_tprintf(_T("szStr1 小于 szStr2\n"));
}
//szStr1 等于 szStr2
}
带时区的字符串比较
默认情况下,如果没有这句设置中文区域设置 setlocale(LC_ALL, "chs");
程序则默认执行setlocale(LC_ALL, "C");
如果我设置了中文区域设置和不设置中文区域设置 _tcscoll()
比较的结果不同,究其理由是_tcscoll()
带时区特征,如为中文区域,则中文字符按照拼音进行比较(和操作系统有关,WINDOW操作系统还可以按照笔划排序)
#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
#include<strsafe.h>
int main()
{
setlocale(LC_ALL, "chs"); // LC_ALL包括LC_COLLATE
TCHAR szStr1[] = TEXT("我爱老王");
// Unicode:11 62 31 72 01 80 8B 73 00 00 多字节:CE D2 B0 AE C0 CF CD F5 00
TCHAR szStr2[] = TEXT("我是老王");
// Unicode:11 62 2F 66 01 80 8B 73 00 00 多字节:CE D2 CA C7 C0 CF CD F5 00
int n = _tcscmp(szStr1, szStr2);
if (n > 0)
_tprintf(TEXT("szStr1 > szStr2\n"));
else if (n == 0)
_tprintf(TEXT("szStr1 == szStr2\n"));
else
_tprintf(TEXT("szStr1 < szStr2\n"));
//
n = _tcscoll(szStr1, szStr2);
if (n > 0)
_tprintf(TEXT("szStr1 > szStr2\n"));
else if (n == 0)
_tprintf(TEXT("szStr1 == szStr2\n"));
else
_tprintf(TEXT("szStr1 < szStr2\n"));
//
}
分割字符串
_ACRTIMP char* __cdecl strtok_s(
_Inout_opt_z_ char* strToken,//要分割的字符串
_In_z_ char const* _Delimiter, //风格符字符串,分隔符字符串中每个字符均为分割符
_Inout_ _Deref_prepost_opt_z_ char** _Context //返回strToken中剩余没有被分割的部分,提供一个字符串的指针的指针即可。
);
_ACRTIMP wchar_t* __cdecl wcstok_s(
_Inout_opt_z_ wchar_t* _String,
_In_z_ wchar_t const* _Delimiter,
_Inout_ _Deref_prepost_opt_z_ wchar_t** _Context
);
#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
#include<strsafe.h>
#include<vector>
int main()
{
std::vector<LPTSTR> vecLpStrs;
TCHAR strToken[] = TEXT("120~130~150~200~250");
TCHAR strDelimit[] = TEXT("~");
LPTSTR lpToken = NULL; //被分割除部分的指针
LPTSTR lpTokenNext = NULL; //剩余未被分割部分的指针
lpToken = _tcstok_s(strToken, strDelimit, &lpTokenNext);
while (lpToken != NULL)
{
vecLpStrs.push_back(lpToken);
lpToken = _tcstok_s(NULL, strDelimit, &lpTokenNext);
}//把分割出来的结果放到容器中
setlocale(LC_ALL, "chs");
for (size_t i = 0; i < vecLpStrs.size(); i++)
{
_tprintf(_T("%s\n"), vecLpStrs[i]);
}
//120
//130
//150
//200
//250
}
#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
#include<strsafe.h>
#include<vector>
#include<iostream>
int main()
{
std::vector<LPTSTR> vecLpStrs;
TCHAR strToken[] = TEXT("4.78~12.5!0.01");
TCHAR strDelimit[] = TEXT("~!"); //~ 和 ! 都是分割符
LPTSTR lpToken = NULL; //被分割除部分的指针
LPTSTR lpTokenNext = NULL; //剩余未被分割部分的指针
TCHAR step[50] = { 0 };
TCHAR range_low[50] = { 0 };
TCHAR range_high[50] = { 0 };
lpToken = _tcstok_s(strToken, strDelimit, &lpTokenNext);
::StringCchCopy(range_low, _countof(range_low), lpToken);
lpToken = _tcstok_s(NULL, strDelimit, &lpTokenNext);
::StringCchCopy(range_high, _countof(range_high), lpToken);
::StringCchCopy(step, _countof(step), lpTokenNext);
setlocale(LC_ALL, "chs");
_tprintf(_T("step = %s\n"), step);
_tprintf(_T("range_low = %s\n"), range_low);
_tprintf(_T("range_high = %s\n"), range_high);
//step = 0.01
//range_low = 4.78
//range_high = 12.5
}
字符串快速排序
#include <Windows.h>
#include<tchar.h>
#include<stdio.h>
#include <locale.h>
#include<strsafe.h>
#include<vector>
#include<iostream>
int main()
{
LPCTSTR arrStr[] = {
TEXT("架构风格之资源管理.AVI"),
TEXT("模块化之合理内聚.AVI"),
TEXT("总结.AVI"),
TEXT("模块化之管理依赖.AVI"),
TEXT("系统架构设计概述.AVI"),
TEXT("架构风格之分布式.AVI")
};
qsort(arrStr, _countof(arrStr), sizeof(LPTSTR), [](const void* arg1, const void* arg2)->int
{
return _tcscoll(*(LPTSTR*)arg2 ,*(LPTSTR*)arg1);
});
setlocale(LC_ALL,"chs");
for (int i = 0; i < _countof(arrStr); i++)
_tprintf(TEXT("%s\n"), arrStr[i]);
//系统架构设计概述.AVI
//模块化之管理依赖.AVI
//模块化之合理内聚.AVI
//架构风格之资源管理.AVI
//架构风格之分布式.AVI
//总结.AVI
}
字符串与数值型相互转化
字符串转数值
double __cdecl atof (_In_z_ char const* _String);
double __cdecl _wtof( _In_z_ wchar_t const* _String ); // 字符串 转双精度浮点型
int __cdecl atoi (_In_z_ char const* _String);
int __cdecl _wtoi(_In_z_ wchar_t const* _String ); //字符串转整型
long __cdecl atol (_In_z_ char const* _String);
long __cdecl _wtol(_In_z_ wchar_t const* _String ); //字符串转长整型
__int64 __cdecl _atoi64(_In_z_ char const* _String); //字符串转64位整型
long long __cdecl _wtoll(_In_z_ wchar_t const* _String); //字符串转long long 长整型
z_ char const* _String);
double __cdecl _wtof( _In_z_ wchar_t const* _String ); // 字符串 转双精度浮点型
int __cdecl atoi (_In_z_ char const* _String);
int __cdecl _wtoi(_In_z_ wchar_t const* _String ); //字符串转整型
long __cdecl atol (_In_z_ char const* _String);
long __cdecl _wtol(_In_z_ wchar_t const* _String ); //字符串转长整型
__int64 __cdecl _atoi64(_In_z_ char const* _String); //字符串转64位整型
long long __cdecl _wtoll(_In_z_ wchar_t const* _String); //字符串转long long 长整型
上述函数,并不要求字符串必须是一个数值形式,比如说某个字符串str是"-1.23456你好,老王",调用_ttof(str)函数返回的结果是double型的-1.23456,函数会跳过前面的空格字符,知道遇到数字或者正负号才开始转换,知道出现非数字或者字符串结束标志时,才结束转换。并把转换后的结果返回。你要相信,人家写库的人,你会怎么调用的情况都想过了的~~~
当然啊,如果开头部分就是不可转换字符,比如说"你好-1.23456你好,老王",则函数返回0.0.