• 听翁恺老师mooc笔记(8)--字符串2


      字符串的赋值

      字符串的输入与输出

      对C语言的基础类型,比如int、double等类型,scanf、printf有专门的格式转换,而对字符串,scanf、printf使用%s格式字符进行输入与输出。当使用scanf进行读一个字符串的时候,读到什么东西,读到什么位置为止是很微妙的,试一下:

    1 #include <stdio.h>
    2 int main(void){
    3     char word[8];
    4     scanf("%s",word);
    5     printf("%s##
    ",word);
    6     
    7     return 0; 
    8  } 
    View Code

      程序在输出时,在%s后面添加两个##,来提示我们输出释放结束。编译运行后输入hello world,结果如下,输出只有hello,没有world,也没有hello和world之间的空格。

    hello world
    hello##
    
    --------------------------------
    Process exited after 5.404 seconds with return value 0
    请按任意键继续. . .
    

      对代码再修改如下,试着能到world,新建了两个字符串,使用scanf读取两次再使用printf输出两次,结果第一次读到的是hello不带空格,第二次读到的是world也不带空格,因为空格是区分hello和world的,是分隔符。如果输入hello会出,然后输入world再回车,输出结果依然是hello##world##,没有回车。

     1 #include <stdio.h>
     2 int main(void){
     3     char word[8];
     4     char word2[8];
     5     
     6     scanf("%s",word);
     7     scanf("%s",word2);
     8     printf("%s##%s##
    ",word,word2);
     9     
    10     return 0; 
    11  } 
    View Code
    hello world
    hello##world##
    
    --------------------------------
    Process exited after 7.528 seconds with return value 0
    请按任意键继续. . .
    

      所以综上,%s读到的是一个“单词”,这个单词不是英文中的单词,而是读到空格、tab或回车为止。可见scanf是不安全的,它不知道要读入的内容的长度是多少,再使用scanf时,没有给scanf任何字符串word有多大,我们再学数组时知道,数组作为函数参数时,传进去的是个指针。再上述程序中,开了8个字节的一个数组,那么当你输入的东西超过8个会怎么样?在32位编译系统中,当输入超过8个时有可能输出部分结果,也有可能运行结果崩溃,崩溃的原因是输入越界了。

      那么给字符串写入时,怎么使scanf函数安全哪?在%s前面加一个7,因为申请8个字节,有一个字节是结束符。程序修改如下:

     1 #include <stdio.h>
     2 
     3 int main(){
     4     char word[8];
     5     char word2[8];
     6     
     7     scanf("%7s",word);
     8     scanf("%7s",word2);
     9     printf("%s##%s##
    ",word,word2);
    10     
    11     return 0; 
    12  } 
    13  
    View Code
    1234567812345678
    1234567##8123456##
    
    --------------------------------
    Process exited after 8.191 seconds with return value 0
    请按任意键继续. . .
    

      当输入1234567812345678时,前7个字符给了第一个scanf,而8123456近邻的这7个字符给了第二个scanf。所以在%和s之间的数字表示最多允许读入的字符的数量,这个数组应该比数组的大小小1.所以有数字控制读多少个,而字符后有没有空格、tab等还有没有用,当读入的个数不超过7个时,出现空格、tab或回车等,依然有效,但当超过7个时,只读入7个字符,因为读入的个数由%和s之间的数字确定。那么读入7个后下面的内容会交给其他scanf等。

      常见错误

      误解1:比如下面代码,使用char*定义后就可以直接使用了,以为char*是字符串类型,定义了一个字符串类型的变量string就以为可直接使用了,但实际上char*只是定义了一个指向某一块内存空间的指针,但是这个指针没有被初始化,然后char*是本地变量,本地变量没有默认的初始值,所以很可能指向一个未知的不可写的空间,那么在使用scanf写入一些东西时,系统就会崩溃。(未见每一次都崩溃,但是早晚有一天就崩溃了,或者在这台电脑没有崩溃,换一台电脑运行同一块代码就会崩溃)。

    char * string;
    scanf(“%s”,string);
    

      误解2:关于空字符串。比如下面代码,相邻的紧挨着”“意思是这是一个空字符串,第一行制定数组是100,依然是一个有效的字符串,但是这个字符串的buffer[0]=''。但第二行没有指定buffer的大小,这个字符串数组的长度是1,不可以写入东西。

    char buffer[100]="";
    char buffer[]="";

      字符串数组

      如果你想写一个数组去表达很多个字符串,char**a,a是一个指针,指向另一个指针,而那个指针指向一个字符(串),所以这不是我们需要的字符串数组。

      char[][]是什么呢,a是一个二维数组的变量,在二维数组中,第二维一定需要一个确切的大小的,否则编译通不过。试一下这件事情,代码如下,编译时出错,错误提示为:4 11 D:Cexamplechar.cpp [Error] declaration of 'a' as multidimensional array must have bounds for all dimensions except the first如我们所述一样,二维数组的第二维需要一个确切的大小。

    1 #include <stdio.h>
    2 
    3 int main(void){
    4     char a[][]={"hello",};
    5     
    6     return 0;
    7 }
    View Code

      那么修改上述代码为 char a[][10]={"hello",};,表示a这个数组里的每个单元是一个char [10],也就是a[0]相当于一个数组,当然这么写,如果输入超过10个字符时,编译器就会出错:4 54 D:Cexamplechar.cpp [Error] initializer-string for array of chars is too long [-fpermissive]

    1 #include <stdio.h>
    2 
    3 int main(void){
    4     char a[][10]={"hello","world","alksjfklasjlkfjsklfj"};
    5     
    6     return 0;
    7 }
    View Code

      那么如果我们将char a[][]改为char *a[],这个时候就不会出错,在这个时候,a[0]相当于char *。这两种形式是不一样的,当定义char a[][10]时,意思是在内存里有一个很大的矩形,每个a[]都是10个字符。而定义成char *a[]的形式,意思是每个元素都比较小,a[0]是一个指针,指向外面的某个地方。

      作业:试着使用字符串数组完成输入月份,那么输出这个月份的英文单词。

      程序参数-主函数参数

      字符串数组还有一个应用就是可作为main函数的参数:int main(int argc,char const *argv[]),main参数表里不是空的,有两个参数,一个是整数,一个是字符串数组,整数是告诉我们后面数组到底有多少字符串的,下面试一下,输出参数中所有字符串,看下到底是些什么?

     1 #include <stdio.h>
     2 
     3 int main(int argc, char const *argv[]){
     4     int i;
     5     for (i=0;i<argc;i++){
     6         printf("%d:%s
    ",i,argv[i]);
     7     }
     8     
     9     return 0;
    10 }
    View Code

      共有argc个字符串,使用for循环,输出每一个字符串,输出格式是”i:字符串内容“,i是从0开始。结果截图如下,目前只有一个字符串,也就是i=0时的字符串,该字符串内容和终端左上角是一样的,也就是第0个参数是可执行文件:

     

      在devc++的运行菜单选择参数,弹出下列对话框,在传递给主程序的参数中输入任意字符串,然后再运行时,结果有四个参数,第0个参数是生成的可执行文件,第1个、2个、3个参数是用户执行该程序的输入,具体有几个参数看用户输入几个。

    0:D:Cexamplechar3.exe
    1:niu
    2:xiao
    3:xia
    
    --------------------------------
    Process exited after 0.02373 seconds with return value 0
    请按任意键继续. . .
  • 相关阅读:
    lc377完全背包问题
    lc650
    lc583
    java static序列化
    lc90回溯
    lc78回溯
    Java基础之常量池
    语法与语义
    数据结构之复杂度分析
    数据结构与算法前言
  • 原文地址:https://www.cnblogs.com/c-programing-language/p/6537006.html
Copyright © 2020-2023  润新知