zoukankan      html  css  js  c++  java
  • 第五次课大纲

    一、回顾6.3节字符数组中字符串的概念:

      1、字符串的定义和初始化

      在C语言中,没有字符串这个数据类型,字符串是以字符数组的形式存在的,并且字符串的末尾会有结束符‘’标志字符串的结束。所以定义以及初始化字符串时,可以使用下列方式:

    char str[]={"hello world"};
    char str[]="hello world";
    

      问题:按照上图方式定义字符数组str,那么str的长度为?

      答案是12,注意不要忽略末尾的结束符,验证方法:sizeof()输出长度

      2、字符串的输入与输出

      字符数组的输入输出有两种方式:一种是使用%c格式符输入或输出一个字符,另一种是使用%s格式符一次输入与输出整个字符串。

      问题:回忆并使用两种方式编程输出上图中str字符数组。

      答案:答案不唯一,只要输出字符串即可,下面代码只是其中的三种方法,结果会输出三次hello world。

     1 #include <stdio.h>
     2 
     3 int main(int argc, char const *argv[]){
     4     int i;
     5     char a[]="hello world";
     6     printf("sizeof a=%lu
    ",sizeof(a));
     7     
     8     i=0; 
     9     while(a[i]!=''){ 
    10         printf("%c",a[i]);
    11         i++;
    12     } 
    13         printf("
    ");
    14     for(i=0;i<sizeof(a);i++){ 
    15         printf("%c",a[i]);
    16     } 
    17     
    18     printf("
    a[]=%s
    ",a);
    19     
    20     return 0;
    21 }
    View Code

    二、字符串和指针

      1、字符串的指针形式定义

      通过数组和指针的学习,我们知道数组可通过指针进行访问(读写),且指针和数组具有天然的联系,可以以指针的形式去访问或者遍历一个数组,也可以以数组的形式去访问指针所代表的那一大片连续的地址空间。数组和指针有着这种联系,字符串在内存里的表达形式是数组,那么定义或访问字符串时可以使用指针也可以使用数组。因此字符串的定义可以使用下述两种方式:

     char *str = "hello";            //指针形式
     char str[] = "hello";           //数组形式 

      上述两种方式均可使用格式符%s和格式符%c输出字符串str的内容。

      问题:使用指针形式定义字符串,且使用%s和%c输出字符串str。

      答案:答案有多种形式,下面的代码可供参考,编译运行后输出两次hello wolrd。另外思考:在下述代码中若使用%c输出,再使用%s输出,也就是将printf ("%s ",str);  放在第10行,结果是否不变?如果变化为什么?(这个思考题其实属于指针和数组内容)

     1 #include <stdio.h>
     2 
     3 int main(void){
     4     char *str="hello world";
     5    
     6     printf ("%s
    ",str);  
     7    
     8     while ((*str)!='')
     9         printf ("%c",*str++);
    10         
    11     return 0;
    12 }
    View Code

      若将printf ("%s ",str)放在第10行再次编译时,只能输出一次hello,world。为什么哪?因为在使用格式符%c输出字符串时,str指针执行了++运算,那么当输出字符串后,str指向了最后一个字符”“,可通过%p输出str的值验证,具体代码如下:

     1 #include <stdio.h>
     2 
     3 int main(void){
     4     char *str="hello world";
     5    
     6     printf ("%p
    ",str);  
     7    
     8     while ((*str)!='')
     9         printf ("%c",*str++);
    10 
    11     printf ("
    %p
    ",str);         
    12     printf ("%s
    ",str);     
    13     return 0;
    14 }
    View Code

      2、数组形式和指针形式定义字符串的区别

      既然可以使用指针形式定义字符串,并且和数组形式定义字符串形式一样可使用格式符%s和%c输出字符串,那么两种定义方式是完全等价的吗?并不是,两种形式的不同体现在给字符串赋值时,如下述代码:

    1 #include <stdio.h>
    2 
    3 int main(void){
    4     char *s={"hello,world"};
    5     s[0]='B';
    6     
    7     printf("here!s[0]=%c
    ",s[0]);
    8 }
    View Code

      上述代码使用指针形式定义字符串,编译运行时会出现错误,但是当将*s改为s[]时,也就是使用数组形式定义字符串,编译运行没有错误,正常输出结果如下:

    here!s[0]=B
    
    --------------------------------
    Process exited after 0.0329 seconds with return value 0
    请按任意键继续. . .
    

      所以指针形式定义的字符串是不可修改的,若定义一个可修改的字符串则需要使用数组的形式定义字符串。那么为什么哪?为什么字符指针的形式不可修改,而数组的形式可修改。

      3、指针形式定义的字符串为什么不可修改

      为什么指针形式定义字符串,字符串不可修改,我们通过下面的这段代码来分析原因:

     1 #include <stdio.h>
     2 
     3 int main(void){
     4     int i;
     5     char *s = "hello,world";
     6     //s[0]='B';
     7     char *s2 = "hello,world";
     8     printf("&i=%p
    ",&i);    
     9     printf("&s=%p
    ",&s);
    10     printf("&s2=%p
    ",&s2);    
    11     
    12     printf("s =%p
    ",s);
    13     printf("s2=%p
    ",s2);
    14     printf("s[0]=%c
    ",s[0]);
    15 }
    View Code

      新建一个整数变量i、字符串s2,给s和s2同样的初值,输出变量i、s和s2的地址:编译可能还是会有警告,先不管警告,运行后发现结果如下:

    复制代码

    &i=000000000062FE4C
    &s=000000000062FE40
    &s2=000000000062FE38
    s =0000000000404000
    s2=0000000000404000
    s[0]=h

    --------------------------------
    Process exited after 0.01247 seconds with return value 0
    请按任意键继续. . .

    复制代码

      从结果可以看出,作为变量i、s、s2地址是相邻的,且先定义的变量的地址大,后定义的变量的地址小。而s和s2的结果是一样的,s和&s结果不一致,变量i、s、s2地址是一个很大的数,而s和s2的值比较小,主要是因为“hello,world”在程序的代码段,地址一般比较小且所在区域一般不允许修改,如果程序修改该区域,那么操作系统会有个保护机制,会让你的代码运行错误,说你在做坏事不让你写,如果该操作系统允许你写,那么这个操作系统不够安全。

      写好程序编译的时候,编译器会对编译时就已经有值(hello,world)的东西,将该值放在一个只读不能写的位置(也就是代码区),然后让你的指针指向这个值的位置,如果有两个指针的值都是这个值,那么就需要将两个指针都指向这个值的位置,也就因为允许多个指针指向这个位置,所以才不允许修改。实际上,s是一个指针,初始化为指向一个字符串常量,由于这个常量在只读不可写的位置,所以实际上s是const char *s,但是由于历史的原因,编译器接收不带const的写法,或者是省略const的写法,但是试图对这个字符串常量做写入会导致严重的后果。

      4、数组形式定义的字符串为什么可修改

      数组形式定义的字符串为什么可修改?在上述代码的基础上再添加数组形式定义字符串s3:

     1 #include <stdio.h>
     2 
     3 int main(void){
     4     int i;
     5     char *s = "hello,world";
     6     char *s2 = "hello,world";
     7     char s3[] = "hello,world";
     8     printf("&i=%p
    ",&i);    
     9     printf("&s=%p
    ",&s);
    10     printf("&s2=%p
    ",&s2);    
    11     printf("&s3=%p
    ",&s3);    
    12     printf("s3=%p
    ",s3);    
    13             
    14     printf("s =%p
    ",s);
    15     printf("s2=%p
    ",s2);
    16     
    17     s3[0]='B';
    18     printf("s3[0]=%c
    ",s3[0]);
    19 }
    View Code

      编译运行结果如下,发现&s3和s3是同一个位置,和i、s、s2都在同一个位置:

    &i=000000000062FE4C
    &s=000000000062FE40
    &s2=000000000062FE38
    &s3=000000000062FE20
    s3=000000000062FE20
    s =0000000000404000
    s2=0000000000404000
    s3[0]=B
     
    --------------------------------
    Process exited after 0.03045 seconds with return value 0
    请按任意键继续. . .

       使用数组形式定义字符串,那么字符串就在当前位置,也就是字符串不会在地址比较小的代码区,而是就在定义当前变量的位置。所以数组形式定义的字符串是可修改的。

      综上所述:当程序需要一个字符串的时候,那么我们是将字符串写成数组的形式还是指针的形式呢?如果是作为数组,那么表示这个字符串就在这里,作为本地变量空间自动被释放。而如果作为指针,那么这个字符串不知道在哪里,所以通常我们使用指针定义字符串完成下列事情:

      1)如果需要一个只读不写的字符串;

      2)如果该字符串需要作为函数参数时,在学指针和数组时我们知道,将数组作为函数参数时,传递到函数内的就是指针;

      3)如果需要动态分配空间,那就只能使用指针了。

      所以,选择指针和数组的基本原则:如果要构造一个字符串,使用数组形式定义字符串,如果要处理一个字符串,使用指针形式定义字符串

    三、字符指针作为函数参数

      字符串存在形式是字符数组,而在上一节说过数组作为函数参数时,传递到函数内部的就是指针,那么练习分别使用字符指针和字符数组的形式传递两个字符串from和to,并且将字符串to的内容复制为字符串from的内容,在赋值的时候可选用指针(*运算符)和数组形式([]运算符)完成。详见课本P259,8.4.2 字符指针作函数参数。

  • 相关阅读:
    flask之视图
    android studio 配置阿里云镜像 加速
    mac idea phpstorm 提示 clear read-only status 解决办法
    如何给网站一键变黑?如哀悼日,一行css代码解决
    Android base64加密中文乱码问题解决记录
    微信Android app支付 重要记录,重要!!
    mysql 数据库拷贝innodb 操作注意事项,宝塔面板
    Linux 服务器使用shell脚本 实现 间隔N秒访问url
    echarts pie饼图块颜色设置
    Linux 服务器 node 节点满了引发的灾难,请定期清理node节点
  • 原文地址:https://www.cnblogs.com/c-programing-language/p/6538257.html
Copyright © 2011-2022 走看看