C语言字符串 *** 作

C语言字符串 *** 作,第1张

C语言字符串 *** 作 程序占用的内存分区形式

一、预备知识—程序的内存分配
一个由c/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)—由编译器自动分配释放,存放函数的参数值,局部变量的值等。

其 *** 作方式类似于

数据结构中的栈。


2、堆区(heap)—一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。

注意它与数据

结构中的堆是两回事,分配方式倒是类似于链表,呵呵。


3、全局区(静态区)(static)—全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态

变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。

程序结束后由系统

释放。


4、文字常量区—常量字符串就是放在这里的。

程序结束后由系统释放。


5、程序代码区

size的用法

size的基本用法和解释

text data bss dec hex filename
1033 276 4 1313 521 a.out

  • text : 正文大小,也就是程序代码区
  • data:包括静态变量和已经初始化的全局变量的数据段大小。

  • bss:由可执行文件中不包含其初始化值的全局变量组成
这是一个前辈写的,非常详细
//main.cpp
int a=0; //全局初始化区
char *p1; //全局未初始化区
main()
{
int b;char s[]="abc"; //栈
char *p2; //栈
char *p3="123456"; //123456/0在常量区,p3在栈上。

static int c=0//全局(静态)初始化区 p1 = (char*)malloc(10); p2 = (char*)malloc(20); //分配得来得10和20字节的区域就在堆区。

strcpy(p1,"123456"); //123456/0放在常量区,编译器可能会将它与p3所向"123456"优化成一个地方。

}

二、堆和栈的理论知识
2.1申请方式
stack:
由系统自动分配。

例如,声明在函数中一个局部变量int b;系统自动在栈中为b开辟空间
heap:
需要程序员自己申请,并指明大小,在c中malloc函数
如p1=(char*)malloc(10);
在C++中用new运算符
如p2=(char*)malloc(10);
但是注意p1、p2本身是在栈中的。


2.2
申请后系统的响应
栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。


堆:首先应该知道 *** 作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,
会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将

该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大

小,这样,代码中的delete语句才能正确的释放本内存空间。

另外,由于找到的堆结点的大小不一定正

好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。


2.3申请大小的限制
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。

这句话的意思是栈顶的地

址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译

时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。

因此,能从栈获得的空间

较小。


堆:堆是向高地址扩展的数据结构,是不连续的内存区域。

这是由于系统是用链表来存储的空闲内存地

址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。

堆的大小受限于计算机系统中有效的

虚拟内存。

由此可见,堆获得的空间比较灵活,也比较大。


2.4申请效率的比较:
栈:由系统自动分配,速度较快。

但程序员是无法控制的。


堆:是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.
另外,在WINDOWS下,最好的方式是用Virtual Alloc分配内存,他不是在堆,也不是在栈,而是直接在进

程的地址空间中保留一块内存,虽然用起来最不方便。

但是速度快,也最灵活。


2.5堆和栈中的存储内容
栈:在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的

地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变

量。

注意静态变量是不入栈的。


当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主

函数中的下一条指令,程序由该点继续运行。


堆:一般是在堆的头部用一个字节存放堆的大小。

堆中的具体内容由程序员安排。


2.6存取效率的比较
char s1[]=“aaaaaaaaaaaaaaa”;
char *s2=“bbbbbbbbbbbbbbbbb”;
aaaaaaaaaaa是在运行时刻赋值的;
而bbbbbbbbbbb是在编译时就确定的;
但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。


比如:
#include
voidmain()
{
char a=1;
char c[]=“1234567890”;
char *p=“1234567890”;
a = c[1];
a = p[1];
return;
}
对应的汇编代码
10:a=c[1];
004010678A4DF1movcl,byteptr[ebp-0Fh]
0040106A884DFCmovbyteptr[ebp-4],cl
11:a=p[1];
0040106D8B55ECmovedx,dwordptr[ebp-14h]
004010708A4201moval,byteptr[edx+1]
004010738845FCmovbyteptr[ebp-4],al
第一种在读取时直接就把字符串中的元素读到寄存器cl中,而第二种则要先把指针值读到edx中,在根据

edx读取字符,显然慢了。


2.7小结:
堆和栈的区别可以用如下的比喻来看出:
使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会

切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。


使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。

自我总结:
char *c1 = “abc”;实际上先是在文字常量区分配了一块内存放"abc",然后在栈上分配一地址给c1并指向

这块地址,然后改变常量"abc"自然会崩溃

然而char c2[] = “abc”,实际上abc分配内存的地方和上者并不一样,可以从
4199056
2293624 看出,完全是两块地方,推断4199056处于常量区,而2293624处于栈区

2293628
2293624
2293620 这段输出看出三个指针分配的区域为栈区,而且是从高地址到低地址

2293620 4199056 abc 看出编译器将c3优化指向常量区的"abc"

继续思考:
代码:

输出:
2293628 4199056 abc
2293624 2293624 abc
2293620 4012976 gbc
写成注释那样,后面改动就会崩溃
可见strcpy(c3,“abc”);abc是另一块地方分配的,而且可以改变,和上面的参考文档说法有些不一定,

#include
using namespace std;

main()
{
char *c1 = “abc”;
char c2[] = “abc”;
char c3 = ( char )malloc(3);
// *c3 = “abc” //error
strcpy(c3,“abc”);
c3[0] = ‘g’;
printf("%d %d %s/n",&c1,c1,c1);
printf("%d %d %s/n",&c2,c2,c2);
printf("%d %d %s/n",&c3,c3,c3);
getchar();
}

字符串声明与使用

定义一个可变的字符串:

char ch[]={“123456abc”};
char ch2[5]={“123456789”}; //会出现警告提示初值太长,可忽略系统将会自动截取

ch[3]=‘B’;

定义一个字符串常量(不可变):

字符常量默认后面后‘\0’作为结束符

char *ch=“123456abc”;//"123456abc"编译时存放在常量区,是不能被改变的。

参考文章

ch[3]=‘B’;//不可用,会出现段错误。

将字符串常量转换成可变字符串可以使用strcpy()函数,将指针变量拷贝到数组中

格式化输入

sprintf:

(1)将数字变量转换为字符串。

(2)得到整型变量的16进制和8进制字符串。

(3)连接多个字符串。

#include
#include

void main() {
	char str[256] = { 0 };
    int data = 1024;
    //将data转换为字符串
    sprintf(str,"%d",data);
    //获取data的十六进制
    sprintf(str,"0x%X",data);
    //获取data的八进制
    sprintf(str,"0%o",data);
    const char *s1 = "Hello";
    const char *s2 = "World";
    //连接字符串s1和s2
    sprintf(str,"%s %s",s1,s2);
}

sscanf :

(1)根据格式从字符串中提取数据。

如从字符串中取出整数、浮点数和字符串等。

(2)取指定长度的字符串

(3)取到指定字符为止的字符串

(4)取仅包含指定字符集的字符串

(5)取到指定字符集为止的字符串

sscanf可以支持格式字符%[]:

(1)-: 表示范围,如:%[1-9]表示只读取1-9这几个数字 %[a-z]表示只读取a-z小写字母,类似地 %[A-Z]只读取大写字母
(2)^: 表示不取,如:%[^1]表示读取除'1'以外的所有字符 %[^/]表示除/以外的所有字符
(3),: 范围可以用","相连接 如%[1-9,a-z]表示同时取1-9数字和a-z小写字母 
(4)原则:从第一个在指定范围内的数字开始读取,到第一个不在范围内的数字结束%s 可以看成%[] 的一个特例 %[^ ](注意^后面有一个空格!)
注意:当sscanf遇到空格,制表符,换行符时,会停止读取。

可以用get来处理更一般的字符串。

//sscanf 的第二个参数,有点像正则表达式,输入的字符串必须匹配第二个字符串参数,然后才能按顺序把字符传递给字符数组。

const char *s = "http://www.baidu.com:1234"; char protocol[32] = { 0 }; char host[128] = { 0 }; char port[8] = { 0 }; sscanf(s,"%[^:]://%[^:]:%[1-9]",protocol,host,port); printf("protocol: %s\n",protocol); printf("host: %s\n",host); printf("port: %s\n",port);

sprintf详解

sprintf(s, “%d”, 123); //产生"123"
可以指定宽度,不足的左边补空格:
sprintf(s, “%8d%8d”, 123, 4567); //产生:" 123 4567"
当然也可以左对齐:
sprintf(s, “%-8d%8d”, 123, 4567); //产生:“123 4567”
也可以按照16 进制打印:
sprintf(s, “%8x”, 4567); //小写16 进制,宽度占8 个位置,右对齐
sprintf(s, “%-8X”, 4568); //大写16 进制,宽度占8 个位置,左对齐

这样,一个整数的16 进制字符串就很容易得到,但我们在打印16 进制内容时,通常想要一
种左边补0 的等宽格式,那该怎么做呢?很简单,在表示宽度的数字前面加个0 就可以了。


sprintf(s, “%08X”, 4567); //产生:“000011D7”

short si = -1;
sprintf(s, “%04X”, si);
产生“FFFFFFFF”,怎么回事?因为spritnf 是个变参函数,除了前面两个参数之外,后面的
参数都不是类型安全的,函数更没有办法仅仅通过一个“%X”就能得知当初函数调用前参数压栈
时被压进来的到底是个4 字节的整数还是个2 字节的短整数,所以采取了统一4 字节的处理方式,
导致参数压栈时做了符号扩展,扩展成了32 位的整数-1,打印时4 个位置不够了,就把32 位整数
-1 的8 位16 进制都打印出来了。

如果你想看si 的本来面目,那么就应该让编译器做0 扩展而不是
符号扩展(扩展时二进制左边补0 而不是补符号位):
sprintf(s, “%04X”, (unsigned short)si);

%o打印8进制,与%x类似,机制与%x一样。

控制浮点数打印格式
浮点数的打印和格式控制是sprintf 的又一大常用功能,浮点数使用格式符”%f”控制,默认保
留小数点后6 位数字,比如:
sprintf(s, “%f”, 3.1415926); //产生"3.141593"
但有时我们希望自己控制打印的宽度和小数位数,这时就应该使用:”%m.nf”格式,其中m 表
示打印的宽度,n 表示小数点后的位数。

比如:
sprintf(s, “%10.3f”, 3.1415626); //产生:" 3.142"
sprintf(s, “%-10.3f”, 3.1415626); //产生:"3.142 "
sprintf(s, “%.3f”, 3.1415626); //不指定总宽度,产生:“3.142”

**连接字符串**
sprintf 的格式控制串中既然可以插入各种东西,并最终把它们“连成一串”,自然也就能够连
接字符串,从而在许多场合可以替代strcat,但sprintf 能够一次连接多个字符串(自然也可以同时
在它们中间插入别的内容,总之非常灵活)。

比如: char* who = "I"; char* whom = "CSDN"; sprintf(s, "%s love %s.", who, whom); //产生:"I love CSDN. " strcat 只能连接字符串(一段以’\0’结尾的字符数组或叫做字符缓冲,null-terminated-string), 但有时我们有两段字符缓冲区,他们并不是以’\0’结尾。

比如许多从第三方库函数中返回的字符数 组,从硬件或者网络传输中读进来的字符流,它们未必每一段字符序列后面都有个相应的’\0’来结 尾。

如果直接连接,不管是sprintf 还是strcat 肯定会导致非法内存 *** 作,而strncat 也至少要求第 一个参数是个null-terminated-string,那该怎么办呢?我们自然会想起前面介绍打印整数和浮点数 时可以指定宽度,字符串也一样的。

比如: char a1[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'}; char a2[] = {'H', 'I', 'J', 'K', 'L', 'M', 'N'}; 如果: sprintf(s, "%s%s", a1, a2); //Don't do that! 十有八九要出问题了。

是否可以改成: sprintf(s, "%7s%7s", a1, a2); 也没好到哪儿去,正确的应该是: sprintf(s, "%.7s%.7s", a1, a2);//产生:"ABCDEFGHIJKLMN" 这可以类比打印浮点数的”%m.nf”,在”%m.ns”中,m 表示占用宽度(字符串长度不足时补空 格,超出了则按照实际宽度打印),n 才表示从相应的字符串中最多取用的字符数。

通常在打印字 符串时m 没什么大用,还是点号后面的n 用的多。

自然,也可以前后都只取部分字符: sprintf(s, "%.6s%.5s", a1, a2);//产生:"ABCDEFHIJKL" 在许多时候,我们或许还希望这些格式控制符中用以指定长度信息的数字是动态的,而不是 静态指定的,因为许多时候,程序要到运行时才会清楚到底需要取字符数组中的几个字符,这种 动态的宽度/精度设置功能在sprintf 的实现中也被考虑到了,sprintf 采用”*”来占用一个本来需要一 个指定宽度或精度的常数数字的位置,同样,而实际的宽度或精度就可以和其它被打印的变量一 样被提供出来,于是,上面的例子可以变成: sprintf(s, "%.*s%.*s", 7, a1, 7, a2); 或者: sprintf(s, "%.*s%.*s", sizeof(a1), a1, sizeof(a2), a2); 实际上,前面介绍的打印字符、整数、浮点数等都可以动态指定那些常量值,比如: sprintf(s, "%-*d", 4, 'A'); //产生"65 " sprintf(s, "%#0*X", 8, 128); //产生"0X000080","#"产生0X sprintf(s, "%*.*f", 10, 2, 3.1415926); //产生" 3.14" **打印地址信息** 有时调试程序时,我们可能想查看某些变量或者成员的地址,由于地址或者指针也不过是个32 位的数,你完全可以使用打印无符号整数的”%u”把他们打印出来: sprintf(s, "%u", &i); 不过通常人们还是喜欢使用16 进制而不是10 进制来显示一个地址: sprintf(s, "%08X", &i); 然而,这些都是间接的方法,对于地址打印,sprintf 提供了专门的”%p”: sprintf(s, "%p", &i); 我觉得它实际上就相当于: sprintf(s, "%0*x", 2 * sizeof(void *), &i); 利用sprintf 的返回值 较少有人注意printf/sprintf函数的返回值,但有时它却是有用的,spritnf 返回了本次函数调用 最终打印到字符缓冲区中的字符数目。

也就是说每当一次sprinf 调用结束以后,你无须再调用一次 strlen 便已经知道了结果字符串的长度。

如: int len = sprintf(s, "%d", i); 对于正整数来说,len 便等于整数i 的10 进制位数。

下面的是个完整的例子,产生10 个[0, 100)之间的随机数,并将他们打印到一个字符数组s 中, 以逗号分隔开。

#include #include #include int main() { srand(time(0)); char s[64]; int offset = 0; for(int i = 0; i < 10; i++) { offset += sprintf(s + offset, "%d,", rand() % 100); } s[offset - 1] = '\n';//将最后一个逗号换成换行符。

printf(s); return 0; } strftime sprnitf 还有个不错的表妹:strftime,专门用于格式化时间字符串的,用法跟她表哥很像,也 是一大堆格式控制符,只是毕竟小姑娘家心细,她还要调用者指定缓冲区的最大长度,可能是为 了在出现问题时可以推卸责任吧。

这里举个例子: time_t t = time(0); //产生"YYYY-MM-DDhh:mm:ss"格式的字符串。

char s[32]; strftime(s, sizeof(s), "%Y-%m-%d %H:%M:%S", localtime(&t)); printf支持的格式: %c 字符 %d 带符号的整数 %i 带符号的整数 %e 科学计数法,小写e %E 科学计数法,大学E %f 浮点数 %g 使用%e或%f中较短的一个 %G 使用%E或%f中较短的一个 %o 八进制 %s 一串字符 %u 无符号整数 %x 无符号十六进制数,用小写字母 %X 无符号十六进制数,用大写字母 %p 一个指针 %n 参数应该是一个指向一个整数的指针,指向的是字符数放置的位置 %% 一个%符号 %ld 带符号的long int %hd 带符号的short int

字符处理函数

int tolower(char ch)若ch是大写字母(‘A’-‘Z’)返回相应的小写字母(‘a’-‘z’)

int toupper(char ch)若ch是小写字母(‘a’-‘z’)返回相应的大写字母(‘A’-‘Z’)

int _tolower(char ch)返回ch相应的小写字母(‘a’-‘z’)

int _toupper(char ch)返回ch相应的大写字母(‘A’-‘Z’)

int toascii(char c)返回c相应的ASCII

#include
void main(){
   char ch1='j';
   printf("%c\n",tolower('H'));//输出:h
   printf("%c\n",_toupper('h'));//输出:H
   printf("%d\n",toascii('a'));//输出:97
}

测试代码:

#include
#include
#include

void main() {
    printf("%d\n", 123);
    printf("%8d%8d\n", 123,4567);
    printf("%-8d%8d\n", 123,4567);
    printf("%-8x%8X\n", 123,4567);
    printf("%08x%08X\n", 123,4567);
    short si = -1;
    printf("%04X\n", si);//拓展为32位的-1
    printf("%04X\n", (unsigned short)si);//正常打印

    printf("%04o\n", si);//拓展为32位的-1
    printf("%04o\n", (unsigned short)si);//正常打印

    printf("%f\n", 3.1415926);
    printf("%10.3f\n", 3.1415626);
    printf("%-10.3f\n", 3.1415626);
    printf("%.3f\n", 3.1415626);

    //打印整形表达的char,digit,Ox的值
    // int i;
    // for(i = 32; i < 127; i++) {
    //     printf("[ %c ]: %3d 0x%#04X\n", i, i, i);
    // }

    char a1[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
    char a2[] = {'H', 'I', 'J', 'K', 'L', 'M', 'N'};
    printf("%.7s%.7s\n", a1, a2);

    time_t t = time(0);
    char s[32];
    strftime(s, sizeof(s), "%Y-%m-%d %H:%M:%S", localtime(&t));
    printf("%s\n",s);
}
//输出结果
/*
123
     123    4567
123         4567
7b          11D7
0000007b000011D7
FFFFFFFF
FFFF
37777777777
177777
3.141593
     3.142
3.142     
3.142
ABCDEFGHIJKLMN
2019-09-19 10:28:47
*/
字符判断函数

int isalpha(char ch) 若ch是字母(‘A’-‘Z’,‘a’-‘z’)返回非0值,(返回1024)否则返回0

int isalnum(char ch) 若ch是字母(‘A’-‘Z’,‘a’-‘z’)或数字(‘0’-‘9’),返回非0值,否则返回0

int isascii(char ch) 若ch是字符(ASCII码中的0-127)返回非0值,否则返回0

int iscntrl(char ch) 若ch是作废字符(0x7F)或普通控制字符(0x00-0x1F),返回非0值,否则返回0

int isdigit(char ch) 若ch是数字(‘0’-‘9’)返回非0值,否则返回0

int isgraph(char ch) 若ch是可打印字符(不含空格)(0x21-0x7E)返回非0值,否则返回0

int islower(char ch) 若ch是小写字母(‘a’-‘z’)返回非0值,否则返回0

int isupper(char ch) 若ch是大写字母(‘A’-‘Z’)返回非0值,否则返回0

int isprint(char ch) 若ch是可打印字符(含空格)(0x20-0x7E)返回非0值,否则返回0

int ispunct(char ch) 若ch是标点字符(0x00-0x1F)返回非0值,否则返回0

int isspace(char ch) 若ch是空格(’ ‘),水平制表符(’\t’),回车符(’\r’),走纸换行(’\f’),垂直制表符(’\v’),换行符(’\n’) 返回非0值,否则返回0

int isxdigit(char ch) 若ch是16进制数(‘0’-‘9’,‘A’-‘F’,‘a’-‘f’)返回非0值, 否则返回0

#include
void main(){   char ch1='j';
   printf("%d\n",isalpha(ch1));//输出:1024
   printf("%d\n",isalnum(ch1));//输出:8
   printf("%d\n",isdigit(ch1));//输出:0:
}
类型转换

Str->double

头文件:stdlib.h

函数原型:double strtod(const char *nptr,char **endptr);

说明:nptr为原字符串,endptr原字符串转换后抛弃的后面的内容,填写NULL则不返回,原字符串数字前面只能是控制或者加减号。

返回值:正负double值

举个栗子:

#include
#include
void main(){
   char *ch1="  -100.65987ffjj";
   char *endss;
   printf("%lf\n",strtod(ch1,NULL));//输出:-100.659870
   printf("%lf\n",strtod(ch1,&endss));//输出:-100.659870
   printf("%s\n",endss);//输出:ffjj
}

Str->long int

头文件:stdlib.h

函数原型:long int strtol(const char *str, char **endptr, int base)

返回值:长整型,以base提取,然后再转换为long int 类型

参数:

str – 要转换为长整数的字符串。

endptr – 对类型为 char* 的对象的引用,其值由函数设置为 str 中数值后的下一个字符。

base – 基数,必须介于 2 和 36(包含)之间,或者是特殊值 0(如0x开头的自动设置为十六进制等)。

举个栗子:

#include
#include
void main(){
   char *ch1="0101jjx";
   char *endss;
   printf("%ld\n",strtol(ch1,NULL,2));//输出:5
   printf("%ld\n",strtol(ch1,&endss,10));//输出:101
   printf("%s\n",endss);//输出:jjx
}

Str->int

头文件:stdlib.h

原型:int atoi(const char *nptr);

注意:原字符串开头必须是空格或者数字或者加减号

举个栗子:

#include
#include
void main(){
   char *ch1="  11.963xxx";
   printf("%d\n",atoi(ch1));//输出:11
}

str->double

atof() 字符串转换到 double 符点数,使用方法与stoi相似

str->long int

atol() 字符串转换到 long 整型,使用方法与stoi相似

字符串处理函数

长度计算:

strlen()函数:

头文件:string.h

原型:int strlen(const char *str)

返回值:遇到’\0’就返回,返回此之前的字符串长度

举个栗子:

#include
#include
void main(){
   char ch[]={'a','b',',''c'};printf
   ("strlen为:%d\n",strlen()ch);//输出2 }
#

运算符sizeof()

C/C++中的一个 *** 作符(operator),返回是一个对象或者类型所占的内存字节数

举个栗子:

includevoid
main ()char{
[ ch]='b'{,0,'c'};int
   = inx10;printf
   ("ch===sizeof:%d\n",sizeof()ch);//输出:3printf
   ("int===sizeof:%d\n",sizeof()inx);//输出:4}
#

拷贝(替换)函数:

strcpy()函数

头文件:string.h

原型:char *strcpy(char *dest, const char *src);

返回值:将str以’\0’为截止前的字符串替换dest,返回值为dest首地址或者也可以直接访问dest获得最终结果

举个栗子:

includevoid
main ()char{
   [ ch1100]="123456789";char
   * =ch2"abc";printf
   ("%s\n",strcpy(,ch1)ch2);//输出abcprintf
   ("%s\n",)ch1;//输出:abcprintf
   ("%s\n",)ch2;//输出:abcprintf
   ("%c\n",[ch16]);}//输出:7,说明strcpy只是把abc\0复制到了ch1的前4位,printf看到\0就输出了,就不再往后看。

#

strncpy()函数

头文件:string.h

原型:char *strncpy(char *dest, const char *src, int n)

返回值:将src以’\0’或者n长度为截止前的字符串替换dest,返回值为dest首地址或者也可以直接访问dest获得最终结果

注意:这个n值很重要,如果拷贝到了src最后的‘\0’则如同替换效果了,如果拷贝是n的值小于或者等于strlen(),则会保留dest未使用的内容。

举个栗子:

include#
includevoid
main ()char{
   [ ch1100]="123456789";char
   * =ch2"abc";printf
   ("%s\n",strncpy(,ch1,ch2strlen()ch2));//输出:abc456789printf
   ("%s\n",)ch1;//输出:abc456789printf
   ("%s\n",)ch2;//输出:abc}
#

比较函数

strcmp()与strncmp()函数

头文件:string.h

原型:

int strcmp(const char *s1, const char *s2);

int strncmp(const char *s1, const char *s2,int n);

返回值:若参数s1 和s2 字符串相同则返回0,s1 若大于s2 则返回大于0 的值,s1 若小于s2 则返回小于0 的值。

举个栗子:

include#
includevoid
main ()char{
   * =ch1"BCD";char
   * =ch2"BCd";printf
   ("%d\n",strcmp(,ch1)ch2);//输出:-32 printf
   ("%d\n",strncmp(,ch1,ch22));//输出:0}
#

strcasecm()与strncasecm()

忽略字母大小写进行比较,其他类似strcmp()函数

举个栗子

include#
includevoid
main ()char{
   * =ch1"abdc";printf
   ("%d\n",strncasecmp(,ch1"ABC",2));//输出:0}
#

追加函数

strcat()与strncat()函数

头文件:string.h

原型:

char *strcat(char *dest, const char *src)

char *strcat(char *dest, const char *src,int n)

返回值:将src以追加的方式添加到dest中,返回值为dest首地址或者也可以直接访问dest获得最终结果

举个栗子:

include#
includevoid
main ()char{
   [ ch1100]="BCD";char
   * =ch2"123456";printf
   ("%s\n",strcat(,ch1)ch2);//输出:BCD123456printf
   ("%s\n",strncat(,ch1,ch22));//输出:BCD12345612}
1

查找字符

strchr()与strrchr()函数

头文件:string.h

原型:

char *strchr(const char *s,char c) //从左向右

char *strrchr(const char *s,char c) //从右向左

返回值:返回查找到的本身位置,如果查找失败则发货NULL

举个栗子:

 < #include.stdio2h>
 < #include.string3h>
 void main ()4{
 char    * =ch1"1234563221";5
 printf    ("%s\n",strchr(,ch1'3'));//输出:345632216
 printf    ("%s\n",strrchr(,ch1'3'));//输出:32217
 if    (!strchr(,ch1'R'))8{
 printf        ("-------------\n");//成功输出此处9
 }    10
} #

查找字符串

strstr()函数

头文件:string.h

原型

char *strstr(char *str1, const char *str2);//从左向右

返回值:返回查找到的字符串中的首地址

注意:strrstr()函数是不自带的,可以通过strstr()进行模拟

举个栗子:

include#
includevoid
main ()char{
   * =ch1"1234562321";printf
   ("%s\n",strstr(,ch1"23"));//234562321if
   (!strstr(,ch1"5566"))printf{
      ("-------------\n");//成功输出此处}
   }

总结

1、可以通过sprintf将其他类型转换为string,当然也可以完成字符串的拼接。

2、可以通过str->otherType类型的函数,可以将string转换为其他类型,对于固定格式的string,可以采用sscanf函数,读取字符串中对应位置的对应格式的值,存入到对应的变量中。

3、字符串处理函数,可以完成:算长度,查找,拼接,复制,对比等 *** 作。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/662731.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-18
下一篇 2022-04-18

发表评论

登录后才能评论

评论列表(0条)

保存