C语言_0313笔记_字符串:以数组的形式存在/或者是指针/怎么选择?/char */输入与输出/常见错误/数组表达很多字符串(char *a[])/main标准定义

10.1.1 字符串

char word[]={'h','e','l','l','o','!'};//不是字符串
char word[]={'h','e','l','l','o','!','\0'};//是C语言的字符串 又是数组
  • \0:其中就有\0的存在,其意义就是0,可以在这个位置直接放单独的一个0,不加单引号和反斜杠。

这个0就让这word这个变量成为字符串,本质上仍然是一个字符数组,具有了双重功能

字符串(实际上是数组)

  • 单引号的反斜杠0:【标志字符串的结束】直接写0可能是int或者更大的类型

  • 单引号里的0:ASCII码里的0,十进制为48

定义字符串(本质是数组)

  • 有以下几种定义字符串的方法:

  • 第一种:一个名为str的指针指向了一个字符数组Hello这个内容在哪,稍后再说

  • 第二种:现在有一个字符数组名为word,内容为Hello

  • 第三种:有名为line的字符数组,大小为10,其中有前6个(0~5)为Hello+0

字符串常量

  • 像“Hello”这样用双引号括起来的东西叫字符串常量(字面量)

  • “Hello”会被编译器变成一个字符数组放在某处(长度为6,结尾有0)【眼睛所看到的长度+1】

  • 在各种语句中都可以见到,scanf、printf等

  • 两个相邻的字符常量会被自动连接在一起,也可以用斜杠链接

小结

10.1.2 字符串常量与变量

字符串 指针:尝试改变其值

char* s="Hello World!";
这表示s是一个字符串(口头上),其值是HelloWorld。
  • 比如我将第一个字母H改为B并将其输出:

char* s="Hello World!";
s[0]='B';
 
printf("s[0] = %c\n",s[0]);
//编译,没有问题,而运行会报错,而且printf没有执行,说明是在s[0]这一句这里出错了。【代码段 只读】
char* s ="Hello World!";
char* s2="Hello World!";
 
printf("s  = %p\n",s);
printf("s2 = %p\n",s2);
 
printf("s[0] = %c\n",s[0]);

//得到的结果竟然是相同的,而这两个的地址值都远小于正常变量的地址(定义一个int i,其地址为0xbff1fd6c),说明这两个字符串存放在很远的地方。

那么实际上,这样定义的字符串是将HelloWorld放到了程序的代码段,是 只读 的(也就是字符串常量),在编译时候就已经定义好了,然后让指针指向它。

由于这个常量位置特殊,实际上s是const char* s,但编译器也接受现在的写法,试图对一个字符串常量做变更和写入会导致出错。

赋值一样的字符串?

//学习了字符串函数后 可以重新开辟一个新的字符串并且使它等于title

如何修改字符串:用数组定义

//所以如果想要修改字符串,应该用数组定义

char s[]="Hello World!";

这样定义的内部过程是这样:在内存中给数组开辟空间之后,把只读部分的那个字符串拷贝到数组内。于是就可以修改其值

char s[] = "Hello World";
 
s[0] = 'B';
printf(s[0] = %c\n, s[0]);

这样就完成了之前做不到的事情。

二者的区别

我们在定义字符串时,到底用指针还是数组呢?

char *str = "Hello";

char s[] = "Hello";
  • 1. 指针:(不知道这个字符串在哪)只想定义一个常量;用来表达函数参数,因为数组用来做函数参数时候和指针是一样的;分配动态空间malloc;【不可写】

  • 2. 数组:字符串就在数组所在地址,由于是本地变量所以空间在使用后会被回收【是本地变量】

  • 因此想要构造一个字符串,用数组;想要处理一个字符串,用指针。

思考:char*

  1. 字符串可以表达为char *

  1. char* 不一定是字符串

  1. char * 表达这里有一个指针,指针指向一个字节or一串连续的字节,但不一定是字符串

  1. 可能指向单个,可能指向数组

  1. 只有char* 所指的字符数组有结尾的0 ——char* 所指的是个字符串

10.1.3字符串的输入输出

对于字符、整型数据等我们可以用scanf、printf等通过格式化字符进行输入输出,那么对于字符串其实也有特殊字符,%s

输入scanf(什么时候为止)

  • scanf不接收空格、回车、Tab等,会将其视为输入终止。

  • scanf读入单词到空格、回车、制表符\t为止。

//因此当用户输入 Hello World(两个单词中间有空格),输出结果是Hello

char string[8];
scanf("%s",string);//字符串不需要用& 直接指向第一个地址string[0]
printf("%s##\n",string);
~~~~~~~~~~~~~~~~~~~~~~
char word1[8];
char word2[8];
 
scanf("%s",word1);
scanf("%s",word2);
 
printf("%s##%s##\n",word1,word2);

容易溢出的scanf

  • scanf是不安全的读入

  • 因为不知道要读入的内容长度。比如在上方的代码运行时输入:

  • 12345678(回车)12345678(回车)

  • 此时根据版本的不同,可能会报错。根本原因是字符串虽然开了长度8的空间,但最后一位被0占据,因此最多只能接收7个字符。

  • 想要安全输入

  • 需要在scanf("%s",word1);的%s前面加上一位数字且这个数字要比数组长度小1

char word1[8];
scanf("%7s",word1)
//在这种情况下,如果输入超过7个字符,剩下的会被下一个数组接收。此时不是通过空格等分割。

常见错误

  • 把char* string当作字符串。

  • //实际上这只是定义了一个指针变量,要指向的东西还不知道在哪。如果没有进行初始化,不一定会报错,这次运行也许通过了,下次就不一定了。。

  • 使用指针定义字符串的时候,需要初始化,使它指向一个明确的地址

  • 空字符串

  • char string[100]=""; //空字符串(有效的) char string[0]=‘\0’

  • char string[]=""; //这个数组实际上是没用的(无效的),0占据了第一位,因此它的长度是1这里面放不下任何其他字符。

10.1.4 字符串数组

一个数组内包含多个字符串

  • char **a

  • a是一个指针,指向另一个指针,另一个指针指向一个字符/字符串。

  • char [] []

  • 二维数组 ,然而二维数组的第二维必须要有明确的大小

  • 如a[][10],相当于a[ ]是一个数组,数组a[ ]的每一个单元都是char[10],如a[0] = char [10]然而每个数组内的字符长度不能超过10。

  • 若超过10,编译器报错

  • char *a[] , 此时的a[0] 是个指针 相当于 char*(外面某处)

ex曾经的switch case 改进:

//我们可以用数组下标代替月份的数字,在其中包含具体的字符串

#include <stdio.h>
 
int main()
{
    int m;
    char *a[] = { 
        "January",
        "Febrary",
        "March",
        "Aprial",
        "May",
        "June",
        "July",
        "August",
        "September",
        "October",
        "November",
        "December",
    };
    
    scanf("%d", &m);
    
    printf("%s\n", a[m - 1]);
    
    return 0;
}

另一个应用:main的参数(底层)

  • 之前都是直接int mian( )

  • 后来建议 int main(void) //在C语言中,对主函数的参数和返回类型检查并不严格,当不需要命令行参数时,就可以将参数列表设置为void。

  • 现在:

main函数称为主函数,是C语言约定的程序执行入口
其标准的定义格式为: int main(int argc, char *argv[]);
其中,参数的含义为
argc: 执行程序时输入的参数个数,包括可执行程序文件名。
argv:前argc个元素(argv[0]到argv[argc-1]),分别为执行程序时的各项参数值,以字符串方式表达。第argc+1个参数(argv[argc])值为NULL。
返回值为int型,会将返回的值回传给主调进程。
在C语言中,对主函数的参数和返回类型检查并不严格,当不需要命令行参数时,就可以将参数列表设置为void。类似的,如果不需要返回信息给主调进程,返回值也可以设定为void类型。
main函数的参数,也可以看到字符串数组
int main(int argc,char const *argv[])

这个数组多大呢?我们需要另一个参数来告诉我们

#include<stdio.h>
int main(int argc,char const *argv[])
{
    int i;
    for(i=0;i<argv;i++)
    {
        printf("%d:%s\n",i,argv[i]);
    }
 
    return 0;
}

//程序会将你在命令行输入的东西保存到这个数组中,且argv[0]保存的是命令符,起一个快捷方式的作用。

猜你喜欢

转载自blog.csdn.net/Shmily_as33/article/details/129497672