C++ 易混淆的概念-sizeof和strlen、char* 和char[]、*p++和(*p)++

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


简单的说,这两者的区别是:

  1. char []定义的是一个字符数组,注意强调是数组
  2. char * 定义的是一个字符串指针,注意强调是指针

   数组表示字符串数组,数组的每一个元素都是一个字符,修改一个数组指的是修改数组的值,即改变其中一个或者多个元素的值;而指针表示这是一个地址,其值就是一个地址,并没有字符串值的概念,修改一个指针只是把指针指向别的地址或者NULL;

定义数组变量ch1和字符串指针ch2。

1   char ch1[] = "ABCDEFGH";
2   char * ch2 = "abcdefgh";
  1. ch1的内容存储在函数栈中,可以被修改,函数一旦返回空间就被释放。
  2. ch2的内容保存在只读数据段中,不可被修改,其空间不会被释放。

总结一下,回到开头提到的:

  1. ch1强调的是数组,ch2强调是指针,在各自作用域范围内有效,可操作。
  2. 作为数组可以操作的是数组值,那么数组内容是可以改变的
  3. 作为指针可以操作的是指针值,那么指针内容是可以改变的,即指向另一个地址但不能改变指针指向的内容。换句话说就是可以修改指针的值,但不能修改指针值的值。

注意   指针内容   和    指针指向的内容    这两个说法的不同之处。前者是地址,后者是地址中存的变量。

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.

  1. *++p 先将指针p自增1(此时指向数组第二个元素),* 操作再取出该值
  2. ++*p 先取指针p指向的值(数组第一个元素1),再将该值自增1,

可以看出这两个操作与*p++和(*q)++,正好是反着操作,前者先计算后赋值,后者是先赋值后计算。

from:https://zhidao.baidu.com/question/494193523.html

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值