文章目录
前言:学过的东西好久不用就会忘掉,也许这就是所谓的“用进废退”吧!
所以这里对C(++) 对字符串、指针等知识点做一个小小的总结.
补充(2022-10-30):这篇博文是之前所作的笔记,现在看来好简陋,对框架进行了简单的修补,内容基本没变。
Part.I 字符串 char*
Chap.I 读入字符串
cin
方法
char line[100];
cin>>line;
scanf
方法
char line[100];
scanf("%s",line);//注意不是&line
scanf
会自动添加结尾的\0
scanf
读入到空格为止
cin.getline
方法
//cin.getline(char buf[],int bufSize);
char line[100];
cin.getline(line,sizeof(line));
读入一行(行长度不超过
bufSize-1
)或bufSize-1
个字符到buf,自动添加\0
回车换行符不会写入buf,但是会从输入流中去掉。如果这一行的字符数超过bufSize-1 ,实际上只取前bufSize-1 个字符,后面的存放在输入流中,不会报错。
gets
方法
//gets(char buf[]);
char line[100];
gets(line);
- 读入一行,自动添加’\0’
- 回车换行符不会写入buf,但是会从输入流中去掉。可能导致数组越界!所以要确保buf 数组足够的大
Chap.II 输出字符串
cout
方法
cout<<str;
printf
方法
printf("%s",line);
Chap.III 字符串函数
#include <cstring> //所要包含的头文件
1.字符串拷贝
strcpy(char[] dest,char[] src);//将src拷贝到dest中
2.字符串比较大小(字典序 前小后大)
int strcmp(char[] s1,char[] s2);//s1<s2,返回负数,s1=s2,返回0
3.求字符串长度
int strlen(char[] s);
4.字符串拼接
strcat(char[] s1,char[] s2);//s2拼接到s1后面
5.字符串转换大小写
strupr(char []);//转大写
strlwr(char []);//转小写
形参为char[]
类型,则实参可以是char
数组或字符串常量。
本来想好好自己写一下的,但是写到这里发现一个特牛的博客,里面对此介绍的内容是我见过的最详尽的,传送门如下:
https://blog.youkuaiyun.com/xfjjs_net/article/details/79329030
以上就是 C
语言中的字符串知识点
除此之外,C++
中还提供了string 这一字符串对象
传送门:门 1
Part.II 字符串 string
上面介绍了C
语言中char*
类型的字符串,在C++
中有更好用的string
类型的字符串,需要以下include
#include <string>
switch
的表达式中不能用char *
或者string
。
Chap.I 字符串初始化
string strs //生成空字符串
string s(str) //生成字符串str的复制品
string s(str, stridx) //将字符串str中始于stridx的部分作为构造函数的初值
string s(str, strbegin, strlen) //将字符串str中始于strbegin、长度为strlen的部分作为字符串初值
string s(cstr) //以C_string类型cstr作为字符串s的初值
string s(cstr,char_len) //以C_string类型cstr的前char_len个字符串作为字符串s的初值
string(num, c) //生成一个字符串,包含num个c字符
string(strs, beg, end) //以区间[beg, end]内的字符作为字符串s的初值
Chap.II 字符串函数
列个大表格,除了构造函数,成员函数的调用方法都是s.xx()
函数名称 | 功能 | 备注 |
---|---|---|
构造函数 | 产生或复制字符串 | |
析构函数 | 销毁字符串 | |
=,assign | 赋以新值 | |
swap | 交换两个字符串的内容 | |
+=,append(),push_back() | 添加字符 | |
insert() | 插入字符 | str.insert(1,s); 在原串下标为1 的字符前插入字符串s |
erase() | 删除字符 | s.erase(beg,len); |
clear() | 移除全部字符 | |
resize() | 改变字符数量 | |
replace() | 替换字符 | |
+ | 串联字符串 | |
==,!=,<,<=,>,>=,compare() | 比较字符串内容 | |
size(),length() | 返回字符数量 | 这两个无区别 |
max_size() | 返回字符的最大可能个数 | |
empty() | 判断字符串是否为空 | |
capacity() | 返回重新分配之前的字符容量 | |
reserve() | 保留内存以存储一定数量的字符 | |
[],at() | 存取单一字符 | |
>>,getline() | 从stream中读取某值 | |
<< | 将值写入stream | |
copy() | 将内容复制为一个C-string | |
c_str() | 将内容以C-string形式返回 | |
data() | 将内容以字符数组形式返回 | |
substr() | 返回子字符串 | 这个比较常用,s.substr(beg,len) |
find() | 搜寻某子字符串或字符 | find(str,position) 从位置position 开始搜寻,返回str 第一次出现的首字母的位置。 |
begin(),end() | 提供正向迭代器支持 | |
rbegin(),rend() | 提供逆向迭代器支持 | |
get_allocator() | 返回配置器 |
不会用看这俩:
string常用函数用法总结
string类及其成员函数汇总
Part.III 指针
Chap.I 指针存在的意义
有了指针,就有了自由访问内存空间的手段,不需要通过变量,就能对内存直接进行操作。通过指针,程序能访问的内存区域就不仅限于变量所占据的数据区域! 往往在写底层的,比较接近硬件的应用程序的时候要用到指针。有了指针,就可以做很多“出格”的事情了,比如:病毒的注入或者在别的应用程序存储空间里面杀病毒……
T * p; //T可以是任何类型的名字,比如int,double
p 的类型:T *
*p 的类型: T //*p 等价于存放在地址p 开始的sizeof(T)个字节
// "*" 称为间接引用运算符.
// "&"称为取地址运算符
- 通过表达式
*p
,可以读写从地址p
开始的sizeof(T)
个字节 - 对于类型
T
的变量x
,&x
表示变量x
的地址(即指向x
的地址)&x
的类型是T *
- 不同类型的指针,如果不经过强制类型转换,不能直接互相赋值。
Chap.II 指针的运算
- 两个同类型的指针变量,可以比较大小
- 两个同类型的指针变量,可以相减
T * p1,p2;
p1 - p2 =(地址p1 - 地址p2)/sizeof(T)
指针变量加减一个整数的结果还是指针
int n;
T * p;
p+n //表示T * 类型的指针,指向地址p+n*sizeof(T);
指针可以用下标运算符[]
进行运算
T * p;
int n;
p[n]=*(p+n);
Chap.III 空指针
- 地址
0
不能访问。指向地址0
的指针就是空指针 - 可以用
NULL
关键字对任何类型的指针进行赋值。NULL
实际上就是整数0,值为NULL的指针就是空指针。如:
int * pn=NULL;
char * pc=NULL;
int * p2=0;
指针可以作为条件表达式使用。如果指针的值为NULL,则相当于为假,值不为NULL,就相当于为真。
if(p) <=> if(p!=NULL)
if(!p) <=> if(p==NULL)
Chap.IV 数组与指针
- 数组的名字就是一个指针,但它是一个常量,指向数组的起始地址,你不能让它指向别处,作为函数形参时,
T * p
和Tp[]
等价。
指针与二维数组
若 T a[M][N];
a[i]
(i是整数) 是一个一维数组a[i]
的类型是T *
sizeof(a[i])=sizeof(T) * N
a[i]
指向的地址:数组a 的起始地址+i*N*sizeof(T)
指向指针的指针
T **p;
p
是指向指针的指针,p
指向的地方应该存放着一个类型为 T *
的指针 *p
的类型是T *
指针与字符串
字符串常量的类型是char *
字符数组名的类型是char *
, 就是一个地址
Chap.V void 指针
void * p;
- 可以用任何类型的指针对
void
指针进行赋值或初始化; - 因
sizeof(void)
没有定义,所以对于void *
类型的指针p
,* p
无定义
头文件 cstring
中声明:
void * memset(void *dest,int ch,int n);
//将从dest 开始的n 个字节,都设置成 ch .返回值是dest ch只有最低的字节起作用。
void * memcpy(void *dest, void *src,int n);
//将地址src开始的n个字节,拷贝到地址dest,返回值是dest
使用例子
下面是几个例子
// eg1:将szName的前10个字符,都设置成'a':
char szName[200]="";
memset(szName,'a',10);
// eg2:将数组内容全部设置为0:
int a[100];
memset(a,0,sizeof(a));
// eg3:将数组a1 的内容拷贝到a2 中去
int a1[10],a2[10];
memcpy(a2,a1,10*sizeof(int));
Chap.VI 函数指针
程序运行期间,每个函数都会占用一段连续的内存空间。而函数名就是该函数所占内存区域的起始地址(也称“入口地址”)。我们可以将函数的入口地址赋给一个指针变量,使该指针变量指向该函数。然后通过指针变量就可以调用这个函数。这种指向函数的指针变量称为“函数指针”
定义形式:
类型名(* 指针变量名)(参数类型1,参数类型2,……)
使用方法:
#include <cstdio>
void PrintMin(int a, int b)
{
if (a < b) printf("%d", a);
else printf("%d", b);
}
int main()
{
void(*pf)(int, int);
int x = 4, y = 4;
pf = PrintMin;
pf(x, y);
return 0;
}
Part.IV 区别与转换
C++ 中涉及字符串的类型,如果大体分类的化可以只分为两类char *
和string
。但细分的话,其实有很多种,下面列了一个表:
类型 | 说明 |
---|---|
char | 用单引号'' 引起来的一个字符,可以重新赋值 |
char [] | 指针常量,可以理解为char * (const xx) ;其值(指向)不能更改;但是其指向目标(在内存中的区域)的内容可变。最后有一个 '\0' 结束符作为字符串的结束标志。 |
char * | 指针变量,其值(指向)可以改变,可以通过它来更改指向区域的内容 |
const char * | 指针变量,其值(指向)可以改变,但是只能指向常量,不能通过它来更改指向区域的内容,通过别的或许可以。 |
char const * | 等价于const char * |
char * const | 指针常量,其值(指向)不能更改;但是可以通过它来更改指向区域的内容 |
string | C++ 新增的一个类,用双引号"" 引起来的字符串,对其操作十分灵活。要引用头文件#include <string> |
CString | 常用于MFC 编程中,是属于MFC 的类 |
Chap.I 区别
C++中用单引号''
括起来的一个数字、字母或符号表示一个char
,用双引号括起来的一串数字、字母或符号表示一个字符串。主要是关于char*, CString, string
之间的区别
char*
是一个指向字符的指针,是一个内置类型。可以指向一个字符,也可以表示字符数组的首地址(首字符的地址)。我们更多的时候是用的它的第二的功能,来表示一个字符串,功能与字符串数组char ch[n]
一样,表示字符串时,最后有一个'\0'
结束符作为字符串的结束标志。string
是C++
标准库(STL)中的类型,它是定义的一个类,定义在<string>
头文件中。里面包含了对字符串的各种常用操作,它较char*
的优势是内容可以动态拓展,以及对字符串操作的方便快捷,用+
号进行字符串的连接是最常用的操作。CString
常用于MFC
编程中,是属于MFC
的类,如从对话框中利用GetWindowText
得到的字符串就是CString
类型,CString
定义在<afx.h>
头文件中。CString(typedef CStringT> CString
)为Visual C++中最常用的字符串类,继承自CSimpleStringT
类,主要应用在MFC和ATL编程中,所以使用CString时要包含afx.h
文件#include <afx.h>
。
从灵活度来说,string
最灵活易用,其次是CString
,char*
的拓展性和灵活性比较差。 一般来说在基于标准库开发时用string
,在 MFC 和 ATL 编程时用CString
。
ps:关于string是否是STL中的一员众说纷纭,可以将它视为STL中的一员,但是也许在其他地方也可能说它不是STL中的一员。
另外,关于头文件的区别:
头文件 | 描述 |
---|---|
string.h | 旧的 C 头文件,对应的是基于char* 的字符串处理函数; |
string | 包装了std 的C++ 头文件,对应的是新的string 类; |
cstring | 对应于旧C 头文件的std 版本。 |
是这么个意思:一般C
里带.h
扩展名的库文件,比如iostream.h
,在新标准后的C++
标准库中都有一个不带.h
扩展名(iostream
)的与之相对应(有时加上c
的前缀表示来自于C
),区别除了后者的好多改进之外,还有一点就是后者的东东都塞进了std
命名空间(namespace
)中。
Chap.II 转换
关于三者之间的相互转换:
char *
转换为string
:string s3 = string(ch);
string
转换为char *
:const char *ch1 = str.c_str();
char *
转换为CString
:CString cStr2 = CString(ch);
CString
转换为char *
char* chs=cstr.getbuffer(0);
string
转换为CString
:CString cstr(s1.c_str());
CString
转换为string
:str = LPCSTR(cstr4);
可以看到,他们之间的转换,是以char *
作为桥梁的,更为详细的 C++ 数据类型转换可参看博文。