C语言风格字符串的概念、定义、输入字符串、输出字符串

字符串: C语言中最有用、最重要的数据类型之一。

字符串:是以\0字符结尾的char类型数组。所以可以把数组和指针知识应用于字符串。

如何在程序定义字符串:

1、字符串字面量

用双引号括起来的内容称为字符串字面量,也叫作字符串常量。双引号中的字符和编译器自动加入末尾的\0字符,都作为字符串储存在内存中。

如果要在字符串内部使用引号,必须要在双引号前面加上一个反斜杠(\

字符串字面量被视为const,就不能更改了。

字符串常量属于静态存储类别。这说明如果在函数中使用字符串常量,该字符串只会被储存一次,在整个程序的生命期内存在,即使函数被调用多次。用双引号括起来的内容被视为指向该字符串储存位置的指针。

2、字符串数组和初始化

定义字符串数组时,必须让编译器知道需要多少空间,一种方法是足够空间的数组储存字符串。

指定数组大小的时候,必须确保数组的元素个数至少比字符串长度多1

省略数组初始化声明中的大小,编译器会自动计算数组的大小;

 

数组表示法_创建字符串:char words[MAXLENGTH]=“I am a string in an array.”

指针表示法_创建字符串:char * pt1 = “Something is pointing at me.”

3数组和指针

数组表示法_创建字符串:char words[MAXLENGTH]=“I am a string in an array.”

              这种表示法,字符串字面量被存储在静态存储区。数组只有在运行时才会被分配内存。此时,才将字符串拷贝到数组中。此时字符串有两个副本,一个是在静态内存中的字符串字母量,另一个是储存在words数组中的字符串。

       指针表示法_创建字符串:char * pt1 = “Something is pointing at me.”

              编译器为字符串在静态存储区预留了29个元素的空间。一旦开始运行程序,它就会为指针变量pt1留出一个储存位置,并把字符串的地址储存在指针变量中。

4数组和指针的区别

       char heart[] = “I love Tillie!”;  ->数组名heart是常量;

       const char *head = “I love Millie!”; ->指针名是head变量;

       head =heart ->可以;

       heart =head –>不可以,非法构造,赋值运算符左边必须是变量

5、字符串数组

       const char *mytalents[LIM]={

    "Adding number swiftly",

    "Multiplying accurately",

    "Stashing data",

    "Following instructions to the letter",

    "Understanding the C language"

};

 

    char yourtalents[LIM][SLEN]={

    "Walking in a straight line",

    "Sleeping","Watching television",

    "Mailing letters","Reading email"

};

 

字符串数组分配内存的使用率低。因为数组中储存着字符串字面量的副本。每个字符串都被储存了两次。

 

如果要使用数组表示待显示的字符串,建议使用指针数组。指针数组也有缺陷,就是字符串字面量不能更改。如果要改变或者为字符串输入预留空间,不要使用指向字符串字面量的指针。

++++++++++++++++++++++++++++++++++++++++++++++++++++++

字符串的输入:

想把字符串读入程序,首先必须预留储存该字符串的空间。然后用输入函数获取该字符串。

如何分配空间:

  要做的第1件事就是分配空间。以储存稍后读入的字符串。意味着必须为字符串分配足够的空间。不能指望计算机在读取字符串时顺便计算它的长度。

       char *name;

       scanf(“%s”,name);

       name是未初始化的指针,name可能指向任何地方。所以可能会擦写掉程序中的数据或代码,从而导致程序异常中止。

 

       最简单的办法:在声明时显式指明数组的大小。

       char name[81];

 

       现在name是一个已分配块(81字节)的地址。还有一种办法就是使用C库函数来分配内存。

       

  空字符:

      用于标记C字符串末尾的字符;对应的字符ASCII编码是0;

  空指针:

有一个值,该值不会与任何有效的地址对应。

  本质上讲空字符是整数类型,占1个字节;

  空指针是指针类型,是一个地址,占4个字节。

  丢弃输入行中余下的字符,是因为,输入行中多出来的字符会被留在缓冲区中。成为下一次读取语句的输入。

  

  1、gets() 函数    这个函数不安全,被摒弃了

  scanf()和转换说明%s只能读取一个单词,可是在程序中经常要读取一整行输入,而不仅仅是一个单词。

很久前gets()就用于处理这种情况。gets()函数简单易用,它读取整行输入,直至遇到换行符。

gets()函数有个问题,无法检查数组是否装得下行。数组名会被转换成数组首元素的地址。get()函数只知道数组的开始处,并不知道数组中有多少个元素。

如果输入字符串过长,会导致缓冲区溢出(buffer overflow)。多余的字符超出了指定的目标空间。如果这些多余的字符只是占用了尚未使用的内存,就不会立即出现问题。但是一旦擦写掉程序中的其他数据,就会导致程序异常中止。

C99标准建议不要使用get()函数,甚至被C11标准摒弃了。

  

  2、fgets()函数

  函数原型:char *fgets(char *buf, int bufsize, FILE *stream);  ---->从指定的文件读取一个字符串

buf 字符型指针,指向存储读入数据的缓冲区的地址;---->存到哪

n 从流中读入n-1个字符;--->读多少个

stream 指向读取的流;   --->从哪读                                                                                  

会在读入的最后一个字符后加上串结束标志'\0'

返回值:读取失败或读到文件结尾返回NULL;输入成功时,返回 char 型指针,指向读入的字符串内容,含换行键;

  为什么会有换行符问题:因为输入时会敲回车嘛,就产生换行符。函数会把换行符一并存储起来。(读一行字符串的范畴)

  fgets()会存储换行符,有好处也有坏处。好处就是:检查末尾有没有换行符就知道是否读取了一整行。坏处就是:你可能并不想把换行符储存在字符串中,这样的换行符会带来一些麻烦。

  如何处理掉换行符:在已经储存的字符串中查找换行符,将其替换成空字符

while (words[i] != ‘\n’)

i++;

words[i]=’\0’;

  

  3、gets_s()函数

  函数原型: gets_s(words,STLEN);

        只从标准输入中读取数据,不需要第3个参数;

        如果读到换行符,会丢弃它,而不是储存它;(不存换行符)

        如果读到最大STLEN字符数的话,.....很复杂;

        没有fgets()函数灵活,易用;不建议用;

 

  4、s_gets()函数

函数实现如下:

 1 char * s_gets(char * st, int n)
 2 {
 3     char * ret_val;
 4     int i=0;
 5 
 6     ret_val = fgets(st, n, stdin); //读取成功,返回一个指针,指向输入字符串的首字符;
 7     if(ret_val)
 8     {
 9         while(st[i]!='\n' && st[i]!='\0')
10             i++;
11         if(st[i] =='\n') //fgets会把换行符也吃进来了,fgets会在末尾自动加上\0;
12             st[i]='\0';
13         else   //其实是'\0'
14             while(getchar() != '\n')  //会把缓冲区后续的字符都清空
15                 continue;
16     }
17     return ret_val;
18 }

特性:1、会吃进换行符,但是会将其替换成\0空字符;2、会把\0后续的缓冲区内容都清空,为的是不干扰下次输入;

 

  5、scanf()函数

  函数原型:int scanf(const char * restrict format,...);

  返回一个整数值:该值等于sanf()成功读取的项数或EOF(文件结尾)。文件结尾不存在于文件中,而仅仅是一种标志,流的状态的标志。

scanf("%d %d",&a,&b);
函数返回值为int型。如果a和b都被成功读入,那么scanf的返回值就是2;
如果只有a被成功读入,返回值为1;
如果a和b都未被成功读入,返回值为0;
如果遇到错误或遇到end of file,返回值为EOF。end of file为Ctrl+z 或者Ctrl+d。

++++++++++++++++++++++++++++++++++++++++++++++++++++++

字符串的输出:

1、puts()函数

自动在字符串末尾加上换行符,\n

函数只用来输出字符串,没有格式控制,里面的参数可以直接是字符串或者是存放字符串的字符数组名。

2、fputs()函数

int fputs(const char *str, FILE *stream); ---->向指定的文件写入一个字符串;

str  这是一个数组;

stream 指向FILE对象的指针,该FILE对象标识了要被写入字符串的流。

3、printf()函数

函数的输出格式很多,可以根据不同格式加转义字符,达到格式化输出。

posted @ 2018-11-10 08:51  Grooovvve  阅读(2138)  评论(0编辑  收藏  举报