C/C++ 字符串一文全解

字符串的存储,输出,修改:

单个字符串:

  由于C语言没有字符串数据类型,因此字符串使用字符数组进行存储。同时由于最后一个字符默认为’/0’,因此字符数组申请时要比字符串中字符个数多1。

char s[10]= "zhangsan";		//限定数组最大长度为10
printf("%s", s);
char s[]= "zhangsan";		//不限定数组最大长度,数组长度随后面字符长度确定。
printf("%s", s);

//下面的操作是允许的。字符指针按字符串输出,遇到第一个/0结束。
char *a;
a = s
printf("%s", a);

//下面的代码也可以正确的输出zhangsan但是该字符串存储在静态存储区,内容不可以被改变
//s[0] = 'c';语句会报错,该存储区的内容是只读的。
//赋值语句会报warning,表示从字符串常量到字符指针的转换已弃用,但程序依然可以执行。
char *s= "zhangsan";
//s[0] = 'c';
printf("%s",s);
printf("%c",*s);	//按字符输出后面的变量不能是一个地址了,必须是一个字符,这样可以输出字符串的第一个字符。

  扩展: 虽然我们可以使用字符串指针来输出字符串,但是却不能用指针定义通常能够直接定义的数据类型。

//下面的转变会报错,禁止从int到int *的转变。
int *d= 784;
printf("%d",d);
//下面的转变会报错,禁止从char到char *的转变。
char *c= 'z';
printf("%c",*c);

  所以除了字符串可以使用外,其他的并不能使用,并且字符串的使用也会报warning,官方并不建议使用这种方法。

  除此之外,字符串的赋值也只能在变量初始化时进行赋值,对于初始化未赋值的变量,只能通过strcpy函数进行赋值,不能直接通过等号赋值。(数组名代表了该数组的首地址,char s[10];代码系统将为你开辟一个10字节的存储空间,当变量作用域结束时系统会通过该变量的地址释放该开辟的存储空间。而字符串在C语言中如果不是变量初始化时存储到栈区,则其存储在静态存储区,为字符串常量,一般我们用于只读该数据。如果我们将该字符串常量的首地址赋值给变量,变量将无法被修改,同时原来申请的空间的首地址也将丢失,无法被系统回收。)

char s[10];
//下面的赋值操作时错误的,"wenti"字符串是const char[6],不能转换为char[10]
s = "wenti";
printf("%s", s);
//使用string.h头文件中的strcpy函数可以实现此操作。
strcpy(s,"wenti");
printf("%s", s);

  总的来说,单个字符串最好使用char s[]= “zhangsan”;定义,定义时就将其初始化最为合适。

存储多个字符串:

1、二维字符串数组(以输出张三为例)

char a[4][10]= {
    
    "zhangsan", "lisi", "wangwu", "zhaoliu"};
printf("%s", a[0]);
printf("%c", a[0][0]);	//可以输出字符z
//将'a'声明为多维数组时,除第一个维度外的所有维度都必须有边界  
char a[][10]= {
    
    "zhangsan", "lisi", "wangwu", "zhaoliu"};	
printf("%s", a[0]);
printf("%c", a[0][0]);	//可以输出字符z

//这样的转换是无法进行的
char **p = a;

a[0][8] = 'h';	//这种形式的赋值操作可以改变二维字符数组的某个特定位置的值。
//下面的赋值操作无法执行,和上边的单个字符串的非初始化赋值原因一样。
a[0] = "hiiggigi";
//和上边的一样,可以使用string.h头文件中的strcpy函数进行赋值操作。
strcpy(a[0],"wenti");
printf("%s", a[0]);
strcpy(a[0],a[1]);	//这种操作也是合法的
printf("%s", a[0]);

在内存中的存储:

z h a n g s a n /0 /0
l i s i /0 /0 /0 /0 /0 /0
w a n g w u /0 /0 /0 /0
z h a o l i u /0 /0 /0

  可以看到,存储单元中有较多的/0,因此这部分内存是被浪费的,所以有了下面的以为一维数组存储方式。

2、一维指针数组

//和单个字符串用指针赋值一样,该赋值语句会报warning,表示从字符串常量到字符指针的转换已弃用,但程序依然可以执行。
char *n[4]= {
    
    "zhangsan", "lisi", "wangwu", "zhaoliu"};
//和二维数组存储方式不同的是,下面的赋值语句可以执行,因为该指针数组在栈区是四个存储单位为指针,字符串存于静态存储区。
//将字符串的地址给数组的操作可行,栈区的四个存储单位仍能正常回收。当然,同样的其内容将会是只读的,不可更改。
n[0] = "wenti"; 
//静态存储区存储的数据如果是相同的,只会保留一个
//(静态存储区的数据如果是相同的,占用的静态存储区空间大小不变,不同则静态存储区的空间大小要增加。)
printf("%s", n[0]);

//与二维数组不同,下面的转换能够正常进行。
char **m = n;
m[0] = "liuqi";	//赋值操作也是和上面的同理,只读,不可更改字符串内部的某个字符。
//下面的操作是无法进行的。
m[0][0]='c';//该异常不会报错,但会使后续代码无效,等于说系统杀死了该进程。
printf("%s", m[0]);
printf("%c", m[0][0]);

n[0]:

z h a n g s a n /0

n[1]:

l i s i /0

n[2]:

w a n g w u /0

n[3]:

z h a o l i u /0

这样的存储,不会有多余的/0,节约了存储空间。


  总的来说,二维数组的方式可以任意修改数据,但存储空间会大一点。一维指针方式存储空间最小,但数据是只读的,会报warning但不影响运行。

  (如果数据需要多次修改,那么要使用二维数组,因为二维指针的数据修改,被覆盖的数据仍在静态存储区,并没有被覆盖,只是指针位置修改了,而二维数组是真正的原数据被覆盖了,存储空间并不会有所增加。)


字符串输入输出函数:

  上面的分析我们都将字符串预先存入程序,而有些时候字符串需要在程序运行时输入,因此介绍一下字符串的输入输出函数。

字符串输入:

1、char *gets( char *str );

  gets函数会从标准输入设备获取一个字符串存入到str所指向的内存中,回车即字符串输入结束(回车不会被读取)。
  返回值:读取成功返回str的值,读取失败返回NULL。

2、char *gets_s( char *str, rsize_t n );

  gets_s函数和gets函数类似,不同的是它限制了输入的最大字符数,保证了安全性。

3、char *fgets( char *str, int count, FILE *stream );

  fgets函数第一个参数和gets参数作用一致,第二个参数限制输入的最大字符数(最多读取count-1个字符),第三个参数是一个文件指针,可以从文件中读取字符串,如果设置为stdin就是从标准输入设备读取字符串。与gets一样使用回车作为字符串输入结束标志(与gets不同的是回车符将会被读取)。
  返回值:读取成功返回str的值,读取失败返回NULL。

4、​int scanf( const char *format, … );​

  scanf函数读取字符串时使用%s格式控制符的方式来读取。scanf的读取是读取单词的形式,遇到空白符(即空格,制表符,换行符)时结束读取(该空白符不会被读取),并且下一个读取会从下一个非空白符开始,中间的空白符将会被跳过舍弃。%10s指定了最多读取10个字符。由于需要在末尾加上’\0′, 所以最多需要11个存储空间。

字符串输出:

1、int puts( const char *str );

  puts函数和gets相对应,将str字符串输出,遇到/0输出结束。与printf不同的是它会在字符串输出结束后自动换行。

2、int fputs( const char *str, FILE *stream );

  fputs函数第一个参数是要输出的字符串,第二个参数同样的是文件指针,使用stdout宏定义代表标准输出设备。fputs函数不会在字符串的末尾自动换行。

3、int printf( const char *format, … );​

  printf函数使用%s设置为字符串格式输出。它不会自动换行。效率也比puts要低一点。


总结:

  字符串输入:

  如果你需要录入一个单词——使用gets_s()
  如果你需要录入多个单词——使用scanf()
  如果你需要录入带有空格的一句话——使用fgets()

  字符串输出:

  如果你需要输出一个单词自动换行——使用puts()
  如果你需要输出一个单词自己控制知否换行——使用printf()
  如果你需要输出一句带有空格的话——使用fputs()


输入输出单个字符

int getchar();

  getchar从标准输入读一个字符,并返回其ascii码,遇到文件尾则返回EOF

int putchar( int ch );

  在标准输出输出ch。ch会转化为unsigned类型。
成功返回ch的值 不然返回EOF

  char类型其值只能保存ASCII码中的值,输出时可以按字符输出为对应字符,也可以按整数型输出其对应数值。因此getchar和putchar用int来代替char类型。

猜你喜欢

转载自blog.csdn.net/weixin_44350337/article/details/121501524