原创首发于CSDN,转载请注明出处,谢谢!
什么是字符串
与之前的数组做类比,大致可以将字符串看成一个“字符数组”,里面的每一个成员都是字符(char)。
//数组。
int arr[3] = {1,2,3};
//字符串(最费力的定义方法。)
char str[3] = {'a','b','c'};
字符串的定义方式
我们直接在 ubuntu 环境下定义出几个字符串,演示代码 definie.c
。
/* define.c */
#include <stdio.h>
#include <string.h>
int main()
{
//方法一:指定字符串长度。
char str[3] = "abc";
//方法二:让编译器自动计算字符串长度。
char str2[] = "efg";
//方法三:实际开发过程中使用指针偏多且为常量。
char *str3 = "xyz";
return 0;
}
根据以上代码中字符串的定义方式,我们可以自然地对第二种定义方式提出一个小小的疑惑:对于这类不标长度的字符串,我们怎样计算它的大小? 进入下一小节 —— 字符串的长度计算 。
字符串的长度计算
在C语言中提供了两个函数来计算字符串的长度——
s
i
z
e
o
f
(
)
sizeof()
sizeof() 和
s
t
r
l
e
n
(
)
strlen()
strlen() ,直接将上文中的代码拿来运行 str.c
/* str.c */
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "efg";
printf("sizeof:%ld\n", sizeof(str));
printf("strlen:%ld\n", strlen(str));
return 0;
}
运行结果:
根据以上的结果显示,我们可以自然提出:同一个字符串大小为什么不一样?函数 s i z e o f ( ) sizeof() sizeof() 与函数 s t r l e n ( ) strlen() strlen() 的区别是什么?
答:
- 定义字符串时不指定大小时,编译器回会自动在字符串尾部添加一个空字符
\0
。上文中的字符串看似只有三个,但实际上有四个字符。- 函数 s t r l e n ( ) strlen() strlen() 计算的是字符串中的有效位数个字符,当期遇到空字符
\0
后自动停止计数。函数 s i z e o f sizeof sizeof 则计算包含末尾的空字符在内的一切字符个数。
字符串空间的申请及其初始化
演示代码: memoryStr.c
/* memoryStr.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
//方法一:字符串数组。
char str[128] = {'\0'};
//方法二:malloc开辟空间。
char *pstr = NULL;
pstr = (char *)malloc(128);
memset(pstr ,'\0',128);
}
根据以上的代码信心我们提出两个问题:方法二为什么不用野指针而用空指针NULL?方法二相比方法一的优势是什么?
答: 答: 答:
- 空指针NULL表明指针没有动作,即没有指向内存任意地址,需要认为添加。野指针就是乱指。使用空指针比野指针更加安全。
- 方法二比方法一更加灵活。
字符串常用的API
关于常用的字符串 API 数量不多,仅 strcpy、strcat、strcmp、strchr、strstr、strtok、strlwr、strupr。笔者将相关字符串的运行代码直接发在下文内,读者请自行拷贝运行尝试。
|strncpy(拷贝)
演示代码: strcpy. c
/* strcpy. c */
#include <stdio.h>
#include <string.h>
int main()
{
char str1[9] = "ABCDEFOPQ";
char str2[6] = "HIJKLM";
strncpy(str1,str2,6);
puts(str1);
return 0;
}
|strcat(拼接)
演示代码: strcat. c
/* strcat.c */
#include <stdio.h>
#include <string.h>
int main()
{
char str3[] = "hello,";
char str4[] = "world!";
strcat(str3,str4);
puts(str3);
return 0;
}
|strcmp(比较)
strcmp()函数是根据ACSII码的值来比较两个字符串的;strcmp()函数首先将s1字符串的第一个字符值减去s2第一个字符,若差值为零则继续比较下去;若差值不为零,则返回差值。
演示代码: strcmp.c
/* strcmp.c */
#include <stdio.h>
#include <string.h>
int main()
{
char *m="xYZ";
char *n="Xyz";
// 函数原型:int strcmp(const char *s1, const char *s2);
printf("strcmp(m,n):%d\n",strcmp(m,n));
return 0;
}
| strchr(单字符查找)
演示代码: strchr.c
/* strchr.c */
#include <stdio.h>
#include <string.h>
int main()
{
char *str = "chen1,li,chen2";
char c = 'l';
char *p = NULL; //char *p aslo work.
// 函数原型:char *strchr(const char *str, char c)
p = strchr(str,c);
if(p == NULL)
{
printf("No this char.\n");
}else{
printf("Exist.\n");
puts(p);
}
return 0;
}
|strstr(子字符串查找)
函数strstr() 用于判断字符串str2是否是str1的子串。如果是,则该函数返回 str1字符串从 str2第一次出现的位置开始到 str1结尾的字符串;否则,返回NULL。
演示代码: strstr.c
/* strstr.c */
#include <stdio.h>
#include <string.h>
int main()
{
char *str = "chen1,li,chen2";
char *substr = "li";
char *p2 = NULL;
// 函数原型:string strstr( string1,string2)
p2 = strstr(str,substr);
if(p2 == NULL){
printf("No this substr in str.\n");
}else{
printf("Exist.\n");
puts(p2);
}
return 0;
}
|strtok(字符分割)
函数 strtok() 用于分割字符串,具用法可以结合指针数组、循环等。函数原型char *strtok(char s[], const char *delim)
。s为要分解的字符串,delim为分隔符字符串。strtok()用来将字符串分割成一个个片段。参数s指向欲分割[字符串,参数delim则为分割字符串中包含的所有字符。当strtok()在参数s的字符串中发现参数delim中包含的分割字符时,则会将该字符改为\0 字符。在第一次调用时,strtok()必需给予参数s字符串,往后的调用则将参数s设置成NULL。每次调用成功则返回指向被分割出片段的指针。
演示代码: strtok.c
/* strtok.c */
#include <stdio.h>
#include <string.h>
int main()
{
char *p = NULL;
char str2[] = "chen1,li,chen2";
// 函数原型:char *strtok(char s[], const char *delim)
p = strtok(str2,",");
if(p != NULL ){
printf("First ------ p = %s\n",p);
}
p = strtok(NULL,",");
printf("Second ------- p = %s\n",p);
p = strtok(NULL,",");
printf("Three ------ p = %s\n",p);
p = strtok(NULL,",");
printf("Four -------- p = %s\n",p);
return 0;
}
运行结果:
First ------ p = chen1
Second ------- p = li
Three ------ p = chen2
Four -------- p = (null)
|strtok()加指针强化版——pstrtok()
演示代码: pstrtok.c
/* pstrtok.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *p = NULL;
char str2[] = "chen1,jack,chen2,hello,world";
char *psubs[6];
int i = 0;
p = strtok(str2,",");
if(p != NULL )
{
psubs[i] = p;
}
while(1)
{
i++;
p = strtok(NULL,",");
if(p != NULL){
psubs[i] = p;
}else{
// printf("No substrs."\n);
break;
}
}
int j;
for(j = 0;j < i; j++)
{
printf("%s\n",psubs[j]);
}
return 0;
}
//注:字符乱码调试了半小时多,唉!
运行结果: 运行结果: 运行结果:
chen1
jack
chen2
hello
world
|strlwr (字符转小写)、strupr(字符转大写)
/* strlwrStrupr.c */
#include <stdio.h>
#include <string.h>
int main()
{
char p[] = "abc";
char q[] = "ABC";
//字符转大写。
printf("strupr:%s\n",strupr(p));
//字符转小写。
printf("strlwr:%s\n",strlwr(q));
return 0;
}
笔者在此处使用函数 strlwr()
和 strupr()
,GCC 编译器直接给出警告。后经搜索才知,原来C语言中标准库函数不包含这两个函数,只能在windows下(VC、MinGW等)使用,Linux 下的 GCC 里需要自己定义函数去实现。
更新时间记录
- “字符串的定义方式”一节完成。 「2021.4.28 21:36」
- 文章更新到“字符串空间的申请以及初始化”一节。 「2021.4.29 17:46」
- 文章初次竣工,文本中关于字符串函数仍然有疏漏的地方,待后几日补上。 「2021.4.29 21:37」
- 原有的函数功能注释移出代码区。 「2021.4.29 21:46」
- 将文本中原有的错误全部修改了一遍。 「2021.4.30 10:36」
- 大幅度修改“strlwr & strupr”一节。 「2021.4.30 19:34」
- 修改文章标题及部分段落格式。「2024.3.27 11:19」
P.S.1 写博客从来就不是一种轻松的活,哪怕是一篇常识性的博文,累! (2021.4.29 21:38)