;
字符数组,字符指针,字符串常量 知识回顾
1.以字符串形式出现的,编译器都会为该字符串自动添加一个0作为结束符,如在代码中写 "abc",那么编译器帮你存储的是"abc\0"
2."abc"是常量吗?
1.当作为字符数组初始值的时候,"abc"不是常量
char str[] = "abc";
因为定义的是一个字符数组,所以就相当于定义了一些空间来存放"abc",而又因为字符数组就是把字符一个一个地存放的,所以编译器把这个语句解析为
char str[4] = {'a','b','c','\0'};
2.当赋值给 字符指针变量的时候:如char* ptr = "abc" 此时是常量
char* ptr = "abc" //规范不允许这种c的写法
const char* ptr = "abc";
因为定义的是一个普通字符指针,并没有定义空间来存放"abc",所以编译器得帮我们 找地方来放"abc",显然,把这里的"abc"当成常量并把它放到程序的常量区是编译器 最合适的选择。简言之,如果char* ptr = "abc";写在函数体内,那么虽然这里的"abc\0"被 放在常量区中,但是ptr本身只是一个普通的指针变量,所以ptr(指针)是被放在栈上的, 只不过是它所指向的东西(值)被放在常量区罢了
3.数组的类型是由该数组所存放的东西的类型以及数组本身的大小决定的
如char s1[3]和char s2[4],s1的类型就是char[3],s2的类型就是char[4], 也就是说尽管s1和s2都是字符数组,但两者的类型却是不同的
4.字符串常量的类型可以理解为相应字符常量数组的类型
如"abcdef"的类型可以看成是const char[7]
5.sizeof是用来求类型的字节数的。
如int a;那么无论sizeof(int)或者是sizeof(a)都 是等于4,因为sizeof(a)其实就是sizeof(type of a)
6.对于函数参数列表中的以数组类型书写的形式参数,编译器把其解释为普通 的指针类型
void func(char sa[100],int ia[20],char *p)
则sa的类型为char*
ia的类型为int*
p的类型为char*
7.根据上面的总结,来实战一下
1)对于char str[] = "abcdef";就有sizeof(str) == 7,因为str的类型是char[7] str本身可变
2)也有sizeof("abcdef") == 7,因为"abcdef"的类型是const char[7] 字符串常量
3)对于char *ptr = "abcdef";就有sizeof(ptr) == 4,因为ptr的类型是char*,即
#include <iostream>
#include <string>
using namespace std;
int main() {
char *p = "hello";
cout << sizeof(p) << endl; //4
cout << sizeof(char *) << endl; //4
return 0;
4)对于char str2[10] = "abcdef";就有sizeof(str2) == 10,因为str2的类型是char[10]
5)对于void func(char sa[100],int ia[20],char *p);
sizeof(sa) == sizeof(ia) == sizeof(p) == 4,
因为前面有说过编译器把数组类型的书写的形参,解释为普通的指针类型
sa的类型是char*, ia的类型是int*,p的类型是char*
对于C/C++中的 字符指针和字符数组,总是在碰到的时候无法确定而不得不现场测试,来确定末尾是否包含'\0',函数到底如何使用等等。真是劳民伤财,现在总结一下:
字符指针的赋值
(1)指向一个字符串常量
char *src = "abcded"; //这种方式由系统自动给该字符指针指定了一个内存中的位置,并且该位置的字符数组为{'a', 'b', 'c', 'd', 'e', 'd', '\0'};
如果此时再次对 src赋值,src = "mmmt", 则src指向另外一个由系统指定的内存块(由"mmmt"本身返回)。这种方式赋值的src为一个指向字符串常量指针,不能对src指向的位置的内容做改变的操作,即不能执行 *src = 'a', *(src+1) = 't' 等操作;但是可以改变src指向的位置,即像之前的 src = "mmmt";
(2)指向一个字符数组
char tmp[4] = {'a', 'c', 'e', 'f'};
char* src = tmp;
(3)使用 new,然后可以像字符数组一样赋值,即指向一个字符数组
char* src = new char[10]; //这种方式由程序在堆内存上开辟了一个数组,并将地址赋值给src
字符串常量和字符数组比较
(1)字符串常量由系统自动分配一个内存区域,且该区域中的内容不能改变(即无法通过指向该字符串的指针进行修改);
(2)字符数组或者为系统自动分配的全局数据区或栈上的内存,或者通过new操作来分配的堆上的内存,字符数组中的内容可变(即可以通过指向该字符数组的指针进行修改)。
(3)字符数组中不默认含有'\0',除非明确赋值,而字符串常量在末尾自动含有 '\0'.
strcpy的使用
(1)用strcpy时候, 如果源字符串是一个字符指针,则没有问题,因为字符指针自动带'\0',在'\0'位置复制结束;
而如果源是一个字符数组(即将字符数组转换为字符指针来使用),则将会从字符数组的首地址开始复制,如果字符数组中明确指定了'\0'元素,则会在'\0'处停止,而若没有'\0'元素,则程序可能会不停的复制,直到在程序的内存中碰到'\0',这样可能会得到不希望的结果。