strlen计算字符串的长度,以'\0'为字符串结束标志
strlen()是函数,可以计算字符串的长度,不管是数组还是指针,只要遇到第一个‘\0’就为止,hello字符串是这样的{‘h’, ‘e’,‘l’,‘l’,‘\0’,‘o’}的所以strlen(“hello”) = 4。
sizeof是分配的数组实际所占的内存空间大小,计算数据空间的字节数。
例如:
char *str = "1111111abcd";
char str1[9] = {1};
sizeof(str) = 4; //是指指针所占的字节大小,在c/c++中一个指针占4个字节(32位系统)
sizeof(str1) = 9; //字符类型占一个字节,8位
sizeof()是运算符,由于在编译时计算,因此sizeof不能用来返回动态分配的内存空间的大小。返回值跟这些里面所存储的内容没有关系。
具体而言,当参数分别如下时,sizeof返回的值含义如下:
数组-编译时分配的数组空间大小
指针-存储该指针所用的空间大小
类型-该类型所占的空间的大小
对象-对象的实际占用空间大小
函数-函数返回类型所占空间的大小
32位:指针都是 4个字节 注意:int *p; sizeof(p)=4; 但sizeof(*p)相当于sizeof(int);
64位:指针都是 8个字节
int 都是4个字节;char都是1个字节
fromhttps://blog.csdn.net/lby978232/article/details/71172713
from :https://www.cnblogs.com/bixiaopengblog/p/8036429.html
简单的说,这两者的区别是:
- char []定义的是一个字符数组,注意强调是数组。
- char * 定义的是一个字符串指针,注意强调是指针。
数组表示字符串数组,数组的每一个元素都是一个字符,修改一个数组指的是修改数组的值,即改变其中一个或者多个元素的值;而指针表示这是一个地址,其值就是一个地址,并没有字符串值的概念,修改一个指针只是把指针指向别的地址或者NULL;
定义数组变量ch1和字符串指针ch2。
1 char ch1[] = "ABCDEFGH";
2 char * ch2 = "abcdefgh";
- ch1的内容存储在函数栈中,可以被修改,函数一旦返回空间就被释放。
- ch2的内容保存在只读数据段中,不可被修改,其空间不会被释放。
总结一下,回到开头提到的:
- ch1强调的是数组,ch2强调是指针,在各自作用域范围内有效,可操作。
- 作为数组可以操作的是数组值,那么数组内容是可以改变的。
- 作为指针可以操作的是指针值,那么指针内容是可以改变的,即指向另一个地址,但不能改变指针指向的内容。换句话说就是可以修改指针的值,但不能修改指针值的值。
注意 指针内容 和 指针指向的内容 这两个说法的不同之处。前者是地址,后者是地址中存的变量。
char * 和char[]的初始化操作有着根本区别:
测试代码:
char *a=”Hello World”;
char b[]=”Hello World”;
printf(“%s, %d\n”,”Hello World”, “Hello World”);
printf(“%s, %d %d\n”, a, a, &a);
printf(“%s, %d %d\n”, b, b, &b);
结果:
char *a=”Hello World”; 在常量区存了”Hello World”,在栈中存放指针a.所以printf(“ %d\n”, “Hello World”);输出的是Hello World在常量区的地址;printf(“ %d %d\n”, a, &a);第一个输出是a中存放的地址,这个地址就是“Hello World在常量区的地址”,二第二个输出的是:指针a在栈中的位置。
结果可见:尽管都对应了相同的字符串,但”Hello World”的地址 和 a对应的地址相同,与b指向的地址有较大差异;&b==b (因为char b[]=”Hello World”整体都是存放在栈中。b就是个数组名,我们可以理解为在栈位置2030316处,开始存放H,下个位置存放e.......最后存放d)
我们知道,局部变量都创建在栈区,而常量都创建在文字常量区,显然,a、b都是栈区的变量,但是a指向了常量(字符串常量),b则指向了变量(字符数组),指向了自己(&b==b==&b[0])。
说明以下问题:
char * a=”string1”;是实现了3个操作:
1声明一个char*变量(也就是声明了一个指向char的指针变量,在栈中)。
2在文字常量区中开辟了一个空间存储字符串常量”string1”。
3返回这个文字常量区的地址,作为值,赋给这个字符指针变量a ,存放在栈中
最终的结果:指针变量a指向了这一个字符串常量“string1” (注意,如果这时候我们再执行:char * c=”string1”;则,c==a,实际上,只会执行上述步骤的1和3,因为这个常量已经在内存中创建)
PS: 实际上, char * a=”string1”; 的写法是不规范的! ”string1”默认是常量
因为a指向了即字符常量,一旦strcpy(a,”string2”)就糟糕了,试图向只读的内存区域写入,程序会崩溃的!尽管VS下的编译器不会警告,但如果你使用了语法严谨的Linux下的C编译器GCC,或者在windows下使用MinGW编译器就会得到警告。
所以,我们还是应当按照”类型相同赋值”的原则来写代码: const char * a=”string1”; 保证意外赋值语句不会通过编译。
char b[]=”string2”;则是实现了2个操作:
1、声明一个char 的数组,
2、为该数组“赋值”,即将”string2”的每一个字符分别赋值给数组的每一个元素,存储在栈上。
最终的结果:“数组的值”(注意不是b的值)等于”string2”,而不是b指向一个字符串常量。
小结
char * a=”string1”
char b[]=”string2”;
2.a是一个指针变量,a的值(指向)是可以改变的,但a指向的是一个字符串常量,即指向的区域只读,指向的区域的内容不可改变;
3.b是一个指针常量,一个char型数组的名字,也是该数组首元素的地址,是常量,b的值(指向)不能变;但b指向的目标(数组b在内存中的区域)的内容是可变的
4.作为函数的声明的参数的时候,char []是被当做char *来处理的!两种形参声明写法完全等效!
举例说明:
char str1[] = "abc";
char str2[] = "abc";
const char str3[] = "abc";
const char str4[] = "abc";
const char *str5 = "abc";
const char *str6 = "abc"; //指向常量的指针
char *str7 = "abc"; //指向变量的指针,这种写法好像会报错吧??因为"abc"是常量
char *str8 = "abc";
cout << (str1 == str2) << endl;
cout << (str3 == str4) << endl;
cout << (str5 == str6) << endl;
cout << (str7 == str8) << endl;
结果:0 0 1 1.
1、char str1[] = "abc":
这里的"abc"是一个常量,首先会在常量存储区里存储"abc"这个常量,然后会因为"abc"被赋值给str1[],所以在栈中开辟一段内存,内存大小为4个节点(char数组后会自动加一个'\0'),然后就有一个"abc"被保存在栈中。
同理,str2[]中的"abc"也是保存在栈中,只是地址不同。
到此,有三个"abc"被保存起来,一个在常量存储区,另外两个在栈中。
2、const char str3[] = "abc":
对于这种被const(常量)修饰起来的变量,一般也是被保存在常量存储区,但是对于const数组来讲,系统不确定符号表是否有足够的空间来存放const数组,所以还是为const数组分配内存的。所以str3指向的是栈上的"abc"。????
同理,str4[]也是保存在栈中,地址不同。
3、const char *str5 = "abc":
因为"abc"在常量存储区中保存有一份(即使没保存,这样的操作也会新建一份),这里str5定义的时候,嘿,我见过这个,str5就可以开心的直接指向"abc"所在的常量区的地址。
同理str6,str7,str8。与const没有半毛钱关系,const只是使得str5和str6无法指向新的字符串常量(也就是新的地址,因为const修饰,变成了常量,即地址值不能再改变了)。
from:https://blog.csdn.net/u013654125/article/details/79758286
插一句,c++内存被分为5个区,分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
*p++和(*p)++的区别
*p++:是指:指针指向下一个地址,即地址加一,然后取出此时p所指的数据的值。
(*p)++:是指将*p所指的数据的值加一。
C编译器认为*和++是同优先级操作符,且都是从右至左结合的,所以*p++中的++只作用在p上,和*(p++)意思一样;在(*p)++中,由于()的优先级比*和++都高,所以++作用在()内的表达式*p上。
我们先来理解:p++和++p
p=3;
printf("%d",p++); // 3 ,先输出3,后加1
printf("%d",p); //4
printf("%d",++p); // 5, ++p是先加一,后赋值
实例:
int main()
{
int a[]={1,8,5,9,12,6};
int *p=a;
int *q=a;
int x=*p++; //先取指针p指向的值(数组第一个元素1)赋值给x,再将指针p自增1,此时指向a[1]; x=1
int y=(*q)++; //先取指针q指向的值(数组第一个元素1)赋值给y,再将指针q指向的值自增1; y=1,但执行完a[0]=2
cout<<y<<endl<<((*q)++) <<endl<<x<<endl<<(*++p)++<<endl<<a[0];
}
((*q)++) 输出:q指向的值,此时是2,复制后再将指针q指向的值自增1,即a[0]=3;
(*++p)++:根据运算符优先级,先计算括号内内容,++p,首先自增p,此时p指向第3个元素,即指向a[2];然后通过*得到a[2];后置++不立即改变a[2]的值(输出5),而在此表达式之后a[2]值为6.
- *++p 先将指针p自增1(此时指向数组第二个元素),* 操作再取出该值
- ++*p 先取指针p指向的值(数组第一个元素1),再将该值自增1,