1、字符数组
先来想一想什么是字符串:
字符串(character string)是一个或多个字符的序列,如下所示:
双引号不是字符串的一部分。双引号仅告知编译器它括起来的是字符串,正如单引号用于标识单个字符一样。
C语言没有专门用于储存字符串的变量类型,字符串都被储存在char类型的数组中。数组由连续的存储单元组成,字符串中的字符被储存在相邻的存储单元中,每个单元储存一个字符
数组末尾位置的字符\0。这是空字符(null character),C语言用它标记字符串的结束。空字符不是数字0,它是非打印字符,其ASCII码值是(或等价于)0。C中的字符串一定以空字符结束,这意味着数组的容量必须至少比待存储字符串中的字符数多1。因此,程序中有40个存储单元的字符串,只能储存39个字符,剩下一个字节留给空字符。
再来回想一下如何创建和存储一个字符串?
首先我们想到的是数组,对就是用数组存储一个字符串。
先看一下程序
#include<stdio.h>
#include<string.h>// 提供strlen()函数的原型
#define DENSITY 62.4 // 人体密度(单位:磅/立方英尺)
int main()
{
float weight, volume;
int size, letters;
char name[40]; // name是一个可容纳40个字符的数组
printf("Hi! What's your first name?\n");
scanf("%s", name);
printf("%s, what's your weight in pounds?\n", name);
scanf("%f", &weight);
size = sizeof name;
letters = strlen(name);
volume = weight / DENSITY;
printf("Well, %s, your volume is %2.2f cubic feet.\n",name, volume);
printf("Also, your first name has %d letters,\n",letters);
printf("and we have %d bytes to store it.\n", size);
return 0;
}
运行如下:
用数组(array)储存字符串(character string)。在该程序中,用户输入的名被储存在数组中,该数组占用内存中40个连续的字节,每个字节储存一个字符值。
注意一下:注意,在scanf()中,name没有&前缀,而weight有。这里就和我们之前说的数组名字就是地址相符合。
看一下
char name[40];
name后面的方括号表明这是一个数组,方括号中的40表明该数组中的元素数量。char表明每个元素的类型如下图:
字符串看上去比较复杂!必须先创建一个数组,把字符串中的字符逐个放入数组,还要记得在末尾加上一个\0。还好,计算机可以自己处理这些细节。
C primer Plus
2、字符指针
看一下代码:
char *str = "I Love you";
想一下指针str指向内存区域的内容是“ I Love you”,这个区域是内存的常量存储区,若果我们试图去修改这块内存区上的值就会报错
试一下:
#include<stdio.h>
#include<string.h>
int main(void)
{
char *str = "I Love you";
str[0] = 'c';
printf("%s",str);
return 0;
运行上边这段程序机会报错。
虽然我们不能修改常量存储区域的值,但是我们可以修改指针指向的区域;
#include<stdio.h>
#include<string.h>
int main()
{
char *str ="I love you";
str = "my love";
printf("%s",str);
}
这样,指针就指向常量存储区域的另一块区域,这块内存存储的字段是“my love”运行如下:
因为文字是存储在常量存储区域,常量存储区域是只读的,不允许我们修改。如果要想修改我们可以这样做
#include<stdio.h>
#include<string.h>
int main()
{
char *str ;
char ptr[] ="I love you";
str = ptr;
str[0] = 'C';
printf("%s",str);
}
运行结果如下:
这样就可以了,通过数组定义了字符串,字符串的位置就在静态存储区域或者动态存储区域(可以百度一下概念),之后在定义一个字符指针复值指向在这块内存区域,这样我们就可以修改值了。
3、Char *s 与 char s[]
char *s 的s,s指针是指向一块内存区域,它指向的内存区域的大小可以随时改变,而且当指针指向常量字符串时,它的内容是不可以被修改的,否则在运行时会报错。
char s[]的s 是数组对应着一块内存区域,其地址和容量在生命期里不会改变,只有数组的内容可以改变。
#include<stdio.h>
#include<string.h>
int main()
{
char *s1 = "hello";
char s2[] = "hello";
s2=s1; //编译ERROR,
s1=s2; //OK
}
上边的语句s2= s1 错误;我们可以这样理解:
s2是字符数组的名字,只要定义了,那么s2指向的内存就确定了,这样我们就不能修改S2的值了,就比如你的名字上了户口就不能随时改变了,但是我们可以改变今天穿什么衣服s2[0] = ‘y’;这样就可以修改数组里边的值了。
再来看一段代码:
#include<stdio.h>
#include<string.h>
int main()
{
char *s1="hello";
char s2[]="hello";
char *s3=s2; //定义一个指针指向s2的区域
char **s4=&s3; //s2(char[])要用两步才能完成赋值
char **s5=&s1; //s1(char*) 只需一步
printf("s4=[%s]\n",*s4);//打印结果:s4=[hello]
printf("s5=[%s]\n",*s5);//打印结果:s5=[hello]
}
#include<stdio.h>
#include<string.h>
int main()
{
char *s1="hello";
char s2[]="hello";
char **s4=&s2; //s2(
char **s5=&s1; //s1(char*) 只需一步
printf("s4=[%c]\n",*s4);//打印结果:s4=[h]
printf("s5=[%s]\n",*s5);//打印结果:s5=[hello]
}
上边这两段代码的区别:看第二段代码:
如果没有:char *s3=s2; //定义一个指针指向s2的区域
就会运行出错.因为s2的地址是字符串首字母的地址,把s2的地址给指针s4;s4指向的区域就是一个‘h’的值。
第一段代码:char *s3=s2;//把s2指向地内存区域复值给s3;指针s3就代表了那一块区域。(个人理解是这样。)
再来总结一下:
定义一个指针指向字符串,和字符数组定义字符串的额区别:
1、Char * str = “I love you” 可以修改str让str指向别的内存区域例如str= “my love”。Char str[ ] = “I love you ”中字符内容也可以修改。
2、str【】中str不可修改,str是字符的首地址,但是内容可以修改
Char * str=”I love you”;中可以修改str的值,指向其他,但是内容不可以修改不可以通过间接寻址的方式来修改字符串的内容。