C的字符串

本文介绍了C语言中的字符串处理基础知识,包括字符串的连接、数组与指针的关系、字符串的存储方式及字符串函数的使用方法,帮助读者更好地理解和运用C语言中的字符串。

字符串基础

如果多个字符串之间没有间隔或以空格间隔,C会将这些字符串连接在一起形成一个新的字符串

例:char greeting[50]=  "Hello, and" " how are"  "you"" today!"; 的效果与 char greeting[50] = "Hello, and how are you today!"的效果是相同的


数组,指针与字符串

字符串存放在static storage类中,这意味着如果在函数中使用一个字符串常量,在整个程序运行过程中该字符串只会被存储一次,即便是函数被调用了多次。相比之下,一个数组的存储空间在程序开始运行时才被分配。

例:

#include<stdio.h>
#define MSG "I'm special"
void main(void)
{
        const char *p = MSG;
        const char ar[] = MSG;
        printf("address of MSG: %p\n", MSG);
        printf("address of *p: %p\n", p);
        printf("address of ar[]: %p\n", ar);
}

结果中,MSG和p的地址是相同的,与ar不同,因为ar是在程序运行开始后才被分配空间(但ar中元素的值也不能被改变)

被引用的字符串的作用是一个指向字符串储存位置的指针,这种行为类似于数组名的角色是指向数组位置的指针

例:printf("%s, %p, %c\n", "we", "we", "we");  结果是:we, 0x80484f0, w(字符串常量作为指针,指向字符串的第一个字符)

【const char ar[] = "Something";】与【const  char* p = "Something"】的区别:

ar是一个地址常量,编译器会把它当成是与第一个元素的地址(&ar[0])相同的东西,所以,不能更改ar(如ar++),因为这意味着改变字符串常量的地址;

但对指针来说,当运行时,程序会在内存中开辟一个新的空间用来存储指针变量p,然后将常量字符串的地址赋给p。因为p只是一个指针变量,所以可以对其进行更改

所以,p = ar;是合法的,而ar = p;是非法的

字符串是一个常量,如果用一个指针p指向它,p应该被声明为const,因为它不能改变字符串常量的值(但它可以指向其他地方)

例:char* word = "frame"; word[1] = 'l';

这种用法是不合法的,产生的结果是无法定义的,因为编译器可以选择用一个内存区域存储所有相同的字符串。所以,如果要将一个字符串常量赋给一个指针,最好将该指针声明为const;如果要改变一个字符串的内容的话,不要用指针去指向它


声明字符串数组有两种方法:

1. 一个指针数组,每个元素是指向一个字符串的指针,如:const char* sp[5];

2. 每个元素是char型数组的数组,如:char carr[5][40];

前者每个指针指向static memory中的字符串;而后者存储了字符串的副本,所以每个字符串其实都被存储了两遍。后者的内存使用效率是低下的,因为每个字符串都占用了相同的空间。

总之,如果只是想要调用(如显示)字符串的话,使用指针数组更高效;但如果想要改变字符串内容或者用于储存输入时,只能用char型数组的数组

例:const char* msg = "something"; const char* cpy; cpy = msg;

这种情况下并没对字符串进行复制,只是将两个指针指向了同一个字符串。如果真的想复制字符串的话,要是用strcpy()或strncpy()



字符串相关函数:

gets() - puts()

gets()可以读入一整行输入,但无法检查之前定义的char型数组是不是可以容纳得到的输入。如果输入的字符串太长,会产生buffer overflow,超出的字符可能存储到未使用的内存区域而产生问题("Segmentation fault"在Unix系统中表示程序试图访问未分配给它的空间)。gets()会带来严重的安全隐患。(scanf()也会产生overflow,但可以通过指定域宽度避免)

puts()的参数是字符串的地址;它会在所打印字符串的最后加上换行符,效果等同于printf("%s\n", words);


fgets() - fputs() (最好的选择)

fgets()与gets()的不同:

1. fgets()通过第二个参数限制读入字符的个数解决了可能发生的溢出问题。如果这个参数是n,则fgets()会读到n-1个字符或换行符(因为最后还要添加"\0")

2. fgets()会将读到的换行符存储起来;而gets则会抛弃

3. fgets()有第三个参数,指明读取输入的来源。如果是键盘,使用"stdin"

fgets()会返回指向char型的指针,如果正常运行的话,会返回它第一个参数的地址;如果遇到EOF,则会返回空指针;如果产生错误,会返回NULL

fgets()会从上次停止的地方继续读起。由于fgets()会将读到的换行符存储起来,通常与fputs()成对使用。

fputs()与puts()效果相同,只是不会在末尾自动添加换行符

例:fgets(words, LEN, stdin); fputs(words, stdout);


gets_s() 

gets_s()与fgets()的区别:

1. gets_s()只能从stdin读入,因此没有第三个参数

2. 如果gets_s()读到newline,它会将其抛弃(类似gets())

3. 如果gets_s()读到了最大数量的字符却仍未遇到newline,它会:

a) 将目标数组的第一个字符设成'\0'

b) 继续读取但抛弃后面的输入直到遇到newline或EOF

c) 返回空指针,并唤醒一个handler function(可自定义),这个函数可能会终止或退出程序



strlen():返回字符串长度(不包括'\0')

strcat():共有两个参数,将第二个字符串添加到第一个字符串后,返回第一个字符串的地址(第二个字符串不会被改变)。函数并不会检查第一个字符串是否有足够的空间添加第二个,如果的空间不够,会产生overflow

strncat():比strcat()多一个参数,表明最多将第二个字符串的前几个字符添加到第一个字符串中(遇到'\0'停止)

strcmp():如果两个字符串相同则返回0,从第一个字符开始向后进行比较,如果第一个参数的字母序在第二个之前,则返回负值,反之返回正值(可以理解成返回前面减后面)

strncmp():比较两个字符串直到不同或已经比较了第三个参数所指定的字符数

strcpy():将第二个参数指向的字符串复制到第一个参数所指向的数组中(连同'\0'也会一起复制)(可能会发生overflow)。函数的类型是char*,返回值是第一个参数的地址。另外,第一个参数不一定非要指向一个字符串的开头

strncpy():最多将n个字符复制到目标地址,n是第三个参数。如果达到了n却还未遇到'\0'则不会添加'\0',这样会导致前一个字符串不再是字符串

sprintf():与printf()类似,只不过将内容写入一个字符串,所以提供了一个将若干个元素写入一个字符串的方法。第一个参数是目标字符串。例:sprintf(formal, "%s, %19s, %6.2f", last, first, prize);

char* strchr(const char* s, int c):返回一个指针,指向字符串s中第一个字符c出现的位置。如果未找到则返回空指针(可以用来检查一个输入的字符是不是在所要求的范围内,如要求输入"abcde"中的一个,如果输入是ch,则可以strchr("abcde", ch);如果ch不在范围内会返回NULL)

char* strpbrk(const char* s1, const char* s2):返回一个指针,指向s2中的任意一个字符在s1中第一次出现的位置。未找到返回空指针

char* strrchr(const char* s, int c):返回一个指针,指向字符c在字符串s中最后一次出现的位置。未找到返回空指针

char *strstr(const char* s1, const char* s2):返回一个指针,指向s1中s2第一次出现的位置


atoi():将字符串转换为整型数

atof():将字符串转换为double型

atol():将字符串转换为long型

strtol():把字符串转换为long型,三个参数

strtoul():把字符串转换为unsigned long型,三个参数

strtod():把字符串转换为double型,只有两个参数,只能进行十进制

后三个可以识别并汇报字符串中第一个不是数字部分的字符

例:long strol(const char* restrict nptr, char** restrict endptr, int base);  nptr是指向要转换的字符串的指针,endptr指向终止转换的位置(即所转换的数字字符之后的第一个非数字字符)的指针,注意这个指针是指向字符串类型的,base是输入数字的进制


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值