1、字符和字符串的定义(字符用char,字符串用string)
字符定义:在计算机里,所有数据必须以数字的形式表示,字符也不例外。根据 ASCII 码表的规定,每个字符一个数字表示,而这个数字在 0-127 之间。在 C/C++里char/short/int 都可以表示整数,由于字符的数值范围较小,我们选用 char 型变量来代表字符。
如:
char c = 'aa';
char c= ' 1 ';
这些都是错误的字符表示方法,应为字符对应的单引号中只能出现一个字母,并且不能是汉字,不能有多余的空格出现
\ddd 代表的是一个1到3位的八进制数表示的字符。 八进制数101,等于十进制数的65,而65是A的ASCII码,所以如果按字符打印,会打印对应的字符,也就是打印字符A
选项解释:
字符常量只有一个字符 a错
b是特殊字符叫转义字符 b对
c是字符串常量
d 无意义
字符串定义: (1) 以0结束 ;(2) 所有字符是可打印字符
如:
有一个数组a,
char a[6] = {'a', 'b', 'c', 'd' , 0 };a也可以称为一个字符串,以0结束,并且所有字符可打印,这里注意0是没有加单引号的
char a[4] = {'a', 'b', 'c', 'd'};
printf("%s", a)由于字符串不是以0结束,所以打印时,后面会有一些乱码字符。
int a[5] = {'a', 'b', 'c', 'd', 0};字符串是指一串字符,元素类型必须是char类型。这里的数组a的元素类型是int。
①字符的输出%c
![](https://i-blog.csdnimg.cn/blog_migrate/5651f8e3e982280ab9019b5e0d89b4f4.png)
②字符串的输出%s
char str[6] = "hello";
printf("string: %s \n", str);
③字符串的结束符
字符串的末尾必须为一个数字 0 作为结束符,它是一个字符串结束的标识。如果一串字母不以 0 结束,那它就不算是一个有效的字符串。
下面定义了一个字符数组,前 3 个字符是 b,a,d,但末尾并不是 0,那它不是一个有
效的字符串,在用 printf 输出的时候会有问题:
char buf [4] = { 'b' , 'a' , 'd' , -1 };
printf("Got: %s \n", buf);
控制台输出时,会打印出一些乱码字符
而如下的定义就是可行的,末尾为0
由于str[3] 是0,第一个输出abc
第二个输出def
str[7]是0,所以直接结束 ,第三个输出为空
2、strlen()计算出字符串的长度(使用length函数)
字符名称.length()
3、字符串对应的路径输出(\和"之前都必须加上转义符\)
用printf 打印输出以下文本:文件路径: "e:\cprojects\example\test.c"
printf("文件路径: \"e:\\cprojects\\example\\test.c\"");
注意,\ 和 " 均需要转义,\和"之前都必须加上转义符\
这也解释了为什么定义文件名字符串的时候会出现两个斜杠的原因:
如下:\0的应用
4、字符串数组(依次将字符串中的每个字符存入数组中)
char name[10] = "shaofa";
printf("%d, %d, %d \n", name[5], name[6], name[7]);
数组name,初始化为 's' 'h' 'a' 'o' 'f' 'a' 0 0 0 0
name[5] 为 'a' ,即97
name[6] 和 name[7] 为0
字符串赋值给数组,定义为char,将每个字符依次存入数组中
输出是%d,输出字符对应的ASCII码
①字符串数组的赋值(用数组存储字符串和用指针存储字符串)
用数组存储字符串
char name[10] = "shaofa";
name = "shaodong";
上面用法错误,数组的初试化可以直接用等号赋值,但是修改数组不能直接直接将字符串赋值给数组名,如果想修改name里的内容,可以用strcpy_s() 函数。但是可以定义两个字符串数组,用于赋值。
#include <stdio.h>
int mian()
{
char src[]="hello";
char dst[128];
int i=0;
while(1)
{
dst[i]=src[i];
if(src[i]==0)
break;
i++;
}
printf("%s",dst);
return 0;
}
因为字符串中的每一个字符挨个复制到目标缓冲区,所以每一个缓冲区中的类型为char
可以通过打印字符串数组名输出字符串
#include <stdio.h>
#include <string.h>
int main()
{
char name[10] = "shaofa";
strcpy_s(name, 10, "shaodong"); // 修改数组name的内容
getchar();
return 0;
}
strcpy函数中只有两个参数,一个是原数组一个是目标数组,而strcpy_s第二个参数为源目标数组的长度
char* buf = (char*) malloc (128);
buf = "abc";
buf[0] = 'h';
上面用法错误,需要通过函数赋值
char* buf = (char*) malloc (128);
strcpy(buf, "abc"); // 这才是字符串的拷贝,用strcpy把"abc"4个字节拷贝到目标缓冲区
buf[0] = 'h';
由于malloc申请的是缓冲区,返回值为申请地内存的首地址,所以用的指针
指针存储字符串
浅拷贝:指针赋值,连个指针指向同一个字符串对象
char* p1="hello,world";
char* p2=p1;
地址给地址,前面加了*号
字符串指针和字符串数组都是用的char
深拷贝:申请一块相同大小的内存,把字符串内容复制到内存中
char* p2=(char*)malloc(strlen(p1)+1);
strcpy(p2,p1);
通过指针变量也能统计指针字符串的长度
②数组长度必须大于字符串长度(只能多,不能少)
char str[4] = "shao";
printf("值为: %s \n", str);
数组太小,数组长度至少字符串长度+1。此处,字符串 "shao" 长度为4,所以数组长度至少为5。否则,末尾为0作为结束标识,它就不是一个合格的字符串,上述打印中会有乱码。
③字符数组名+整数
#include <stdio.h>
#include <string.h>
int main()
{
char buf[] = "helloworld";
int n1 = strlen(buf);
int n2 = strlen(buf + 4);
buf[0] = 0;
int n3 = strlen(buf);
printf("%d, %d, %d \n", n1, n2, n3);
return 0;
}
n1,n2,n3值分别为10, 6, 0 字符串长度是指:从第一个字符开始,到结束符0,中间字符的个数。buf+4指向第一个字母o。 如果buf[0]为0,即意味着第一个字符就是结束符,所以此时字符串长度为0
5、字符串操作
①截取(取出文件名的前缀和后缀)
当文件名不确定时长度只能此种方法,第二个参数对应的是截取 结束的地方
#include <string>
#include <iostream>
using namespace std;
int main()
{
string name1 = "/a/b/c/v/zhiodfh.jpg";
int pos1 = name1.find_last_of('/');
string name2 = name1.substr(pos1 + 1);
cout << "pos1:" << pos1 << endl;
cout << "文件名:" << name2 << endl;
int pos2 = name2.find('.');
string name3 = name2.substr(0, pos2);
cout << "前缀:" << name3 << endl;
int len = name1.length();
cout << "后缀:" << name2.substr(pos2+1,len) << endl;//<<前后必须加空格
}
头文件必须是<string>和<iostream>,用.h会报错
统计字符串的长度,直接用name.length()
②分割
分割第一次取出192,分割第二次取出168.0.1
将字符串按照逗号分隔开
一个逗号,直接将逗号赋值为空格,记录每一段的起始地址
int main()
{
char str[]="hello,world";
str[5]=0;
char* part1=str;
char* part2=str+6;
printg("%s",part0);
printg("%s",part1);
return 0;
}
字符数组直接赋值给指针
③字符串拼接
方法1:+ 号拼接字符串
方法:2: 使用函数strcat()
#include <stdio.h>
#include<string.h>
int mian()
{
char a[128]="hello";
char b[]="world";
strcat(a,b);
printf("%s",a);
}
将字符串拼接到a上,所以输出内容为a
与方法1中不同的是这里定义的数组
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int maxsize = 32;
char* buf = (char*)malloc(maxsize);
buf[0] = 0;
while(1)
{
// 获取一行
char line[64] = {0};
gets(line);
// 检查如是exit时,退出
if(strcmp(line, "exit") == 0)
{
break;
}
// 检测缓冲区是否够大
int linesize = strlen(line);
int size = strlen(buf);
if(size + linesize > maxsize - 1) // 最多乘放maxsize-1个字节
{
// 申请一个更大的buffer
maxsize += 32;
char* bufnew = (char*)malloc(maxsize);
bufnew[0] = 0;
// 将旧buffer中的字符串拷贝过来
strcpy(bufnew, buf);
size = strlen(bufnew);
// 扔掉旧的buffer
free(buf);
buf = bufnew;
printf("*** 申请更大的缓冲区: %d ***\n", maxsize);
}
// 拼接buffer
strcat(buf, line);
}
printf("-------- result -----------\n");
printf(buf);
// 释放buffer
if(buf) free(buf);
return 0;
}
字符串的多行输入,while(1)中使用gets函数
一定要判断字符串数组的长度和分配的内存的大小关系,字符串长度比内存还大时就需要重新分配内存,释放掉原有内存
字符串拼接使用strcat函数,第一个参数可以是空的指针数组(返回数组的首地址)
④从字符串中取出指定字符(strchr函数),字符串中查找字符
char* s="LiMing";
char* p=strchr(s,'M');
if(p!=NULL)
{
printf("%s\n",p)
}
返回值p指向了字符'M'的地址(返回第一处M出现的位置),获取目标字符的索引可以通过地址操作实现:
int pos=(int)(p-s)
⑤字符串中查找子字符串(strstr函数)
char* s="LiMing is doing homework";
char* p=strchr(s,'M');
if(p!=NULL)
{
printf("%s\n",p)
}
同样可以返回下标索引,通过for循环取出需要的子串(或者通过substr(index,index+子串长度)取出子串)
⑥字符串比较(strcmp函数)
strcmp(a,b)
当a,b字符串的对应位置都相同时,返回0
a<b返回-1,a>b返回1
如果字符串在第二个字符分出高低,剩余字符串不再比较
如:“Jack”和“John”比较时,‘a’<'o',所以“Jack”<“John”
⑦字符串删除
普通方法:通过for循环移动字符串中的字符
当要删除字符串中有多个相同字符且要删除时,需要多次移动,操作复杂。通过新建一个字符串对象
char* erase(const char* text,char del)//传入参数为const char* text不是* test,形参一定要加上类型
{
int len = strlen(text);
char* copy=(char*)malloc(len+1);//新对象的定义直接分配内存,不需要char res[] = {0}
int count = 0;
for (int i = 0;i < len;i++)
{
char ch = text[i];//赋值时记住定义类型
if (ch != del)
{
copy[count] = ch;//变量是count,不是i
count++;
}
}
copy[count] = 0;//这里不需要count+1,因为上一句是后置加
return copy;
}
int main()
{
char input[128] = "China is a great country with a long history";//直接定义字符数组,定义字符串const char*
printf("%s\n", input);
char* copy = erase(input, 'a');
printf("%s", copy);
free(copy);
}
字符串中加空格
利用数组的思想实现(字符串的定义为什么用const char* a?)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void print_string(const char* str)
{
int len = strlen(str);
for (int i = 0; i < len; i++)
{
if (str[i] == 0)
break;
printf("%c ", str[i]);
}
}
int main()
{
const char* a = "abcd";
print_string(a);
return 0;
}
从指针后移的角度考虑(自己)
void print_string(const char* str)
{
int count = 0;
int len = strlen(str);
while (*str)//第一次*str为a
{
printf("%c", *str);//这里打印一定要加上*
count++;
//这里一定不能取等号
if (count < len)//这里不能小于strlen(str),由于str是指针,每次str+1后,str往后移,从而使strlen长度发生变化
printf(" ");
else
break;
str = str + 1;//让指针一直往后指
}
}
int main()
{
print_string("abcd");
return 0;
}
注意:注释的地方是自己之前理解有问题的地方
字符串中删除空格
注意:
①空格表示方法: \t,\t前一定空了一个空格
②在控制台打印string类型的字符串时必须调用c_str()函数,如果不调用程序会报错,因此使用
printf("%s",str.substr(pos1,pos2))的语法是错误的
必须先给一个新的string字符串,然后再通过新的字符串调用c_str()函数来打印
特殊字符转换成表情符
数组思想实现
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void translate(const char* str)
{
int len = strlen(str);
for (int i = 0; i < len; i++)
{
if (str[i] == '/'&& str[i+1] == 's')
{
printf("^_^");
i++;
}
else if (str[i]=='/'&&str[i+1] =='c')
{
printf("T_T");
i++;
}
else if (str[i]=='/'&& str[i+1] == 'f')
{
printf("@_@");
i++;
}
else
{
printf("%c", str[i]);
}
}
}
int main()
{
const char* a = "Thank you/s I will try my best/c";
translate(a);
return 0;
}
同样可以用指针实现(自己在IDE中试一下,和上题解法二的思路相同)
去掉字符串前后空格
直接使用字符串的类find_first_not_of(“ ”),从左/右开始找到第一个不是括号中的字符串
使用字符串的类erase删除对应范围的字符
//去掉首尾空格
string ClearHeadTailSpace(string &str)
{
if (str.empty())
{
return str;
}
int a = str.find_first_not_of(" ");
str.erase(0, str.find_first_not_of(" "));
str.erase(str.find_last_not_of(" ") + 1);
return str;
}
int main()
{
string str = " 123 456 789 ";
cout << ClearHeadTailSpace(str) << endl;
return 0;
}
数字转汉字
方法:不要用if判断是否是1-9,直接定义一个汉字数组,用数字作为汉字数组的下标