上一章 《 c语言指针详解 》
一、 字符串查找字符串个数
strstr中的while和do-while模型
C标准库 – <string.h>
char *strstr
(const char * 要被检索的字符串, const char * 要搜索的小字符串)
该函数返回在 要被检索的字符串 中第一次出现 小字符串 的位置,如果未找到则返回 null。
1)while模型
字符串出现次数
#include <stdio.h>
#include <string.h>
int main() {
//字符串出现次数
char* s = "123456you I wander in your yard, looking forward to meeting you";
char c[] = "you";
int num = 0;
while ((s = strstr(s, c)) != NULL)
{
//有匹配字符串,重新设置起点位置
s = s + strlen(c);
num++;
}
printf("个数: %d\n", num);//3
return 0;
}
C标准库 – <string.h>
strlen()
函数:该函数从第一个字符开始计算字符串中字符数,直到遇到空字符即’\0’为止,然后返回计算字符数的长度,包括’\0’。
2)do-while模型
#include <stdio.h>
#include <string.h>
int main() {
//字符串出现次数
char* s = "123456you I wander in your yard, looking forward to meeting you";
int num = 0;
char c[] = "you";
s = strstr(s, c);
do
{
if (s) { //s!=NULL
num++;
s += strlen(c);
s = strstr(s, c);
}
} while (s);
printf("个数: %d\n", num);//3
return 0;
}
二、 字符串查找字符个数
获取非空格字符串个数(两头堵模型)
只不计算前后的空格,中间的空格会计入。
这个模型就是找两个变量,一个从字符串的开始遍历,另一个从字符串的末尾开始遍历,最后得到中间想要的信息。假设有一个字符串前后都有好多好多空格" Iwanderinyouryard "
, 最后得到前后不为空的子串长度 17。
#include <stdio.h>
#include <string.h>
int fun(char* p, int* n)
{
if (p == NULL || n == NULL)
{
return -1;
}
int begin = 0;
int end = strlen(p) - 1;
//从左边开始
while (p[begin]==' ' && p[begin] != 0)//若果当前字符为空,且没有结束
{
begin++;//位置向右移动一位
}
//从右往左移动
while (p[end] == ' ' && end > 0)
{
end--;//往左移动
}
if (end == 0) {
return -2;
}
//非空元素个数
*n = end - begin + 1;
return 0;
}
int main()
{
char* p = " Iwanderinyouryard ";
int ret = 0;
int n = 0;
ret = fun(p, &n);
if (ret != 0)
{
return ret;
}
printf("个数n:%d\n", n);//17
return 0;
}
所有空格字符都不记
1)数组版
#include <stdio.h>
//获取非空格字符串个数
int GetStrNonBlankCount(char* str)
{
int i = 0;
int count = 0;
while (str[i])
{
if (str[i] != ' ')
{
count++;
}
i++;
}
return count;
}
int main()
{
char str[] = " I wander in your yard ";
int count = GetStrNonBlankCount(str);
printf("非空格字符串个数: %d\n", count);//17
return 0;
}
2)指针版
#include <stdio.h>
//获取非空格字符串个数
int GetStrNonBlankCount(char* str)
{
int count = 0;
while (*str)
{
//if ( *str != ' ')
if (*str != 32) //32是空格
{
count++;
}
str++;
}
return count;
}
int main()
{
char str[] = " I wander in your yard ";
int count = GetStrNonBlankCount(str);
printf("非空格字符串个数: %d\n", count);//17
return 0;
}
字符串去所有空格
#include<stdio.h>
//字符串去空格
void RemoveSpace(char* s)
{
//用来遍历字符串
char* ftemp = s;
//记录非空格字符串的
char* rtemp = s;
while (*ftemp)
{
if (*ftemp != ' ') {
*rtemp = *ftemp;
rtemp++;
}
ftemp++;
}
*rtemp = 0;
}
int main() {
char s[] = " h e l lo x y ";
RemoveSpace(s);
printf("s:%s\n", s);//helloxy
return 0;
}
三、统计不同字符出现的个数
#include <stdio.h>
#include <string.h>
int main(void)
{
char str[] = "iwanderinyouryardlookingforwardtomeetingyou";//97 97+25
int counts[26] = {0};
//直接插入排序
for (int i = 0; i < strlen(str); i++)
{
counts[(str[i] - 'a')]++;
}
for (int i = 0 ;i < 26; i++)
{
if(counts[i])
printf("字母:%c\t出现次数:%d\n", 'a'+i, counts[i]);
}
return 0;
}
注意:char str[] = " I wander in your yard ";
栈区字符串
char* s = “123456you I wander in your yard, looking forward to meeting you”;数据区常量区字符串
四、字符串反转模型(字符串逆置)
1)
#include <stdio.h>
#include <string.h>
void InverseString(char* s)
{
int i = 0;
int j = strlen(s) - 1;
while (i<j)
{
char temp = s[i];
s[i] = s[j];
s[j] = temp;
i++;
j--;
}
}
int main(void) {
char s[] = "looking forward to meeting you";
InverseString(s);
printf("%s\n",s);//uoy gniteem ot drawrof gnikool
return 0;
}
2)
void InverseString(char* s)
{
char* ftemp = s;
char* btemp = s + strlen(s) - 1;
while (ftemp < btemp)
{
char temp = *ftemp;
*ftemp = *btemp;
*btemp = temp;
ftemp++;
btemp--;
}
}
判断是不是回文字符串
末尾和前面都是相同的(是不是对称),例如 abcba 、abccba
#include <stdio.h>
int Symm(char* s) //symmetry
{
char* ftemp = s;
char* btemp = s + strlen(s) - 1;
while (ftemp < btemp)
{
if (*ftemp != *btemp)//不相同
return 1;
ftemp++;
btemp--;
}
return 0;//相同
}
int main()
{
char s[] = "abcba";
int value = Symm(s);
if (!value){//value=0
printf("对称\n");
}
else {
printf("不对称\n");
}
return 0;
}
五、字符串处理函数
字符串拷贝
strcpy
#define _CRT_SECURE_NO_WARNINGS
放在文件开始,防止此文件因为一些老的.c文件使用了strcpy,scanf等不安全的函数导致报警告和错误
,使其无法编译通过,不安全的
。
#include <string.h
>
char *strcpy
(char * dest,const char *src);
把src所指向的字符串复制到dest所指向的空间中,'\0’也会拷贝过去
参数:
- dest: 目的字符串首地址
- src: 源字符首地址
返回值:
- 成功:返回dest字符串的首地址
- 失败:NULL
注意:如果参数 dest 所指的内存空间不够大,可能会造成缓冲溢出的错误情况,所以使用 strcpy 也是不安全的行为。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main() {
char ch[] = "hello xy";
char s[100];
strcpy(s,ch);
printf("%s\n",s);//hello xy
return 0;
}
strncpy
char *
strncpy
(char *dest, const char *src, size_t n);
功能:把src指向字符串的前n个字符复制到 dest 所指向的空间中,是否拷贝结束符看指定的长度是否包含'\0'
。
参数:
- dest:目的字符串首地址
- src:源字符首地址
- n:指定需要拷贝字符串个数
返回值:
- 成功:返回dest字符串的首地址
- 失败:NULL
没有拷贝到’\0’
我们把字符串初始化一下,这样就不会烫烫烫烫烫烫…了
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main() {
char ch[] = "hello xy";
char s[100]={0};
//字符串有限拷贝
strncpy(s,ch,3);
printf("%s\n", s);//hel
return 0;
}
ch总共就9个,拷贝20个会怎么样?
答:可以,拷贝到 ‘\0’ 就结束了
字符串追加
strcat
#include<
string.h
>
char *strcat
(char *dest, const char *src);
功能:将src字符串连接到dest的尾部,'\0' 也会追加过去
。
参数:
- dest:目的字符串首地址
- src:源字符首地址
返回值:
- 成功:返回dest字符串的首地址
- 失败:NULL
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<string.h>
int main(void)
{
char dest[100] = "hello";
char src[] = "world";
strcat(dest, src);
printf("===%s====\n",dest);//helloworld
return 0;
}
如果dest没有足够空间,程序就会挂掉了,没有足够空间就属于数组下标越界了,这里面应该有足够空间去做一个字符串追加。
strncat
char *
strncat
(char *dest, const char *src, size_t n);
功能:把src字符串前n个字符连接到 dest 的尾部,'\0' 也会追加过去
。
参数:
- dest:目的字符串首地址
- src:源字符首地址
- n:指定需要追加字符串个数,大于长度就把整段字符串追加过去了
返回值:
- 成功:返回dest字符串的首地址
- 失败:NULL
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main(void)
{
char dest[100] = "hello";
char src[] = "world";
strncat(dest, src,3);
printf("===%s====\n",dest);//hellowor
return 0;
}
字符串比较
strcmp
#include <
string.h
>.
intstrcmp
(const char *s1,const char *s2);
功能:比较s1和s2的大小、比较的是字符ASCII码大小
。
参数:
- s1:字符串1首地址
- s2:字符串2首地址
返回值:
- 相等:
0
- 大于:>0 在不同操作系统strcmp结果会不同,有的返回ASClI差值,有的是返回
1
- 小于:<0 有的返回ASClI差值,有的是返回
-1
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main(void)
{
char s1[] = "hello xy";
char s2[] = "hello xy";
int val = strcmp(s1,s2);
printf("%d\n",val);//0
return 0;
}
遇到 ‘\0’
strncmp
#include <
string.h
>.
intstrncmp
(const char *s1,const char *s2, size_t n);
功能:比较s1和s2前n个字符的大小、比较的是字符ASCII码大小
。
参数:
- s1:字符串1首地址
- s2:字符串2首地址
- n:指定比较字符串的数量
返回值:
- 相等:
0
- 大于:>0 在不同操作系统strcmp结果会不同,有的返回ASClI差值,有的是返回
1
- 小于:<0 有的返回ASClI差值,有的是返回
-1
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main(void)
{
char s1[] = "hello xy";
char s2[] = "hello xy";
int val = strncmp(s1,s2,5);
printf("%d\n",val);//0
return 0;
}
遇到 ‘\0’
字符串格式化 sprintf
#include <
stdio.h
>
intsprintf
(char *str, const char *format,…);
功能:根据参数format字符串来转换并格式化数据。然后将结果输出到str指定的空间中,直到出现字符串结束符’\0’为止。
参数:
- str:字符串首地址
- format:字符串格式,用法和printf()一样
返回值:
- 成功:实际格式化的字符个数
- 失败:-1
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
char s[100];
//sprintf(s,"hello xy");
//sprintf(s,"%d + %d = %d",1,2,3);
sprintf(s,"===%5d + %05d = %-05d===",1,2,3);
printf("%s\n",s);
return 0;
}
字符串读取数据 sscanf
#include <
stdio.h
>
intsscanf
(const char *str, const char *format,…);
功能:从str指定的字符串读取数据,并根据参数format字符串来转换并格式化数据。
参数:
- str:指定的字符串首地址
- format:字符串格式,用法和
scanf()
一样返回值:
- 成功:参数数目,成功转换的值的个数
- 失败:-1
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
char s[]="a1+12-3";
int a, b, c;
sscanf(s,"%x+%o-%d",&a,&b,&c);
printf("%d,%d,%d\n",a,b,c);//161,10,3
return 0;
}
但是在看这个,当遇到空格或者换行时,跟scanf一样当结束标志处理了
解决办法:我们可以用正则表达式"%[^\n]"
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
char s[] = "hello xy";
char ch[100];
char ch2[100];
//sscanf(s, "%s", &ch);//失败:hello
//sscanf(s, "%9s", &ch);//失败:hello
//sscanf(s, "%[^\0]", &ch);//失败:烫烫烫烫烫烫烫烫烫烫烫烫烫···
//sscanf(s, "%[^\n]", &ch);//hello xy
/* 只截取一部分 */
//sscanf(s, "%3s", &ch);//成功:hel
sscanf(s, "%s%s", &ch, &ch2);//成功:ch="hello" ch2="xy"
//sscanf(s, "%3s%s", &ch, &ch2);//ch="hel" ch2="lo"
printf("===%s===\n", ch);
printf("===%s===\n", ch2);
return 0;
}
字符串查找
字符串里查找字符 strchr
#include <
string.h
>
char *strchr
(const char * s, int c);
功能:在字符换s中查找字母c出现的位置
参数:
- s:字符串首地址
- c:匹配字母(字符)
返回值:
- 成功:返回第一次出现的c地址
- 失败: NULL
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
char s[] = "hello xy";
char c = 'x';
//找得到
char* p = strchr(s, c);
printf("%s\n", p);//xy
//没有找到
c = 'a';
p = strchr(s, c);
printf("%s\n", p);//(null)
return 0;
}
字符串里查找字符串 strstr
#include <
string.h
>
char *strstr
(const char * haystack, const char* needle);
功能:在字符换haystack中查找字符串needle出现的位置
参数:
- haystack:源字符串首地址
- needle:匹配字符串首地址
返回值:
- 成功:返回第一次出现的needle地址
- 失败: NULL
字符串分割(截取) strtok
#include <
string.h
>
char *strtok
(const char * str, const char* delim);
功能:来将字符串分割成一个个片段。当strtok()在参数s的字符串中发现参数delim中包含的分割字符时,则会将该字符改为’\0’字符,当连续出现多个时只替换第一个为’\0’。
参数:
- str:指向欲分割的字符串
- delim:为分割字符串中包含的所有字符
返回值:
- 成功:分割后字符串首地址
- 失败: NULL
strtok会破坏源字符串,用\0替换分割的标志位
,“https://blog.
csdn.net/weixin_59633478/” 变成 “https://blog\0
csdn.net/weixin_59633478/”
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
char s[] = "https://blog.csdn.net/weixin_59633478/";
printf("%p\n", s);//00000088CC70F938
//strtok会破坏源字符串,用\0替换分割的标志位
char* p = strtok(s,".");//"https://blog\0csdn.net/weixin_59633478/"
printf("%p\n",s);//00000088CC70F938
printf("%p\n",p);//00000088CC70F938
printf("%s\n",p);//https://blog
printf("%s\n",s);//https://blog
printf("%c\n",s[13]);//c
return 0;
}
如果还想让字符串继续截取,第二次截取的时候不是s而是NULL
,因为s现在是\0
了,这里面就没有值了而是传递NULL,因为字符串没有截取完,他在缓存区还会保留一份字符串,如果你再想截取就写个NULL。p = strtok(NULL, ".");
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
char s[] = "https://blog.csdn.net/weixin_59633478/";
//https://blog\0csdn\0net/weixin_59633478/
//第一次截取
char* p = strtok(s,".");
printf("%s\n",p);/* https://blog */
//第二次截取
p = strtok(NULL, ".");
printf("%s\n", p);/* csdn */
//第三次截取
p = strtok(NULL, ".");
printf("%s\n", p);/* net/weixin_59633478/ */
return 0;
}
截取邮箱
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
char s[] = "123456789@163.com";
//以@为标志进行截取
char s2[100] = { 0 };
strcpy(s2, s);
//第一次截取
char* p = strtok(s2,"@");
printf("%s\n",p);/* 123456789 */
//第二次截取
p = strtok(NULL, ".");
printf("%s\n", p);/* 163 */
return 0;
}
循环截取
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
char s[] = "I\nwander\nin\nyour yard, looking\nforward\nto\nmeeting\nyou.";
//第一次截取
char* p = strtok(s,"\n");
//判断p是不是NULL
while (p)
{
printf("%s\n", p);
p = strtok(NULL, "\n");
}
return 0;
}
字符串类型转换
a to i
#include <
stdlib.h
>
intatoi
(const char *nptr);
功能:atoi()会扫描nptr字符串,跳过前面的空格字符,直到遇到数字或正负号才开始做转换,而遇到非数字或字符串
结束符(‘\0’)才结束转换,并将结果返回返回值。
参数:
- nptr:待转换的字符串
**返回值:**成功转换后整数,如果失败就是0了
-
类似的函数有:
-
atof()
:把一个小数形式的字符串转化为一个浮点数double类型。 -
atol()
:将一个字符串转化为 long 类型。
#include <stdlib.h>
#include <stdio.h>
int main() {
char s[] = " -123-666abc";
//从+-号或者数字开始识别,遇到非数字就停止
int i = atoi(s);
printf("%d\n", i);//-123
return 0;
}
注意:只能识别十进制的整数