这段代码运行结果为4,4,16,4。
问(1)为什么pArray_No1初始化为指向10个int型的内存地址块(我的理解没错吧?)
而sizeof的运算结果只是1个int型的字节大小,按理来说应该是10个啊,为什么呢?
问(2)pArray_No2=a;说明pArray_No2指向了数组a首元素的地址,sizeof(pArray_No2)
=4,我理解为编译器只计算了数组a首元素地址的内存空间大小;但是问题出来了,a
代表的肯定是数组a首元素的地址,但是这里sizeof(a)=16,说明编译器计算的不是
一个首元素,而是整个数组4个元素的地址占的内存空间。我迷惑了,pArray_No2与
a代表的意义相同,但是为什么sizeof的结果却截然不同呢?
int *pArray_No1,*pArray_No2,a[]={1,2,3,4};
pArray_No1=new int[10];
pArray_No2=a;
cout<<sizeof(pArray_No1)<<endl //结果为4
<<sizeof(pArray_No2)<<endl //结果为4
<<sizeof(a)<<endl //结果为16
<<sizeof(&a[0])<<endl; //结果为4
delete [] pArray_No1;过后我对问题(2)有些自己的理解,不知道是否正确:“pArray_No2指向了数组a首元素的地址”
这个没错,所以pArray_No2储存的就是数组a首元素的地址值,sizeof(pArray_No2)=4那是没错的;
而“a代表的肯定是数组a首元素的地址”这句也没错,但是这里a是数组,数组虽然也算指针,而数组
与指针是有区别的,所以sizeof(a)=16就没错了。然而我的理解只是知其然而不知其所以然,为什么
“数组与指针是有区别的”呢?望爱专细节的朋友帮忙解惑,在下万分感谢!有时候被些问题搞得“食
之无味,夜不能寐”,还好有csdn这个平台,有这么多的好心人帮忙!
问(1)为什么pArray_No1初始化为指向10个int型的内存地址块(我的理解没错吧?)
而sizeof的运算结果只是1个int型的字节大小,按理来说应该是10个啊,为什么呢?
问(2)pArray_No2=a;说明pArray_No2指向了数组a首元素的地址,sizeof(pArray_No2)
=4,我理解为编译器只计算了数组a首元素地址的内存空间大小;但是问题出来了,a
代表的肯定是数组a首元素的地址,但是这里sizeof(a)=16,说明编译器计算的不是
一个首元素,而是整个数组4个元素的地址占的内存空间。我迷惑了,pArray_No2与
a代表的意义相同,但是为什么sizeof的结果却截然不同呢?
int *pArray_No1,*pArray_No2,a[]={1,2,3,4};
pArray_No1=new int[10];
pArray_No2=a;
cout<<sizeof(pArray_No1)<<endl //结果为4
<<sizeof(pArray_No2)<<endl //结果为4
<<sizeof(a)<<endl //结果为16
<<sizeof(&a[0])<<endl; //结果为4
delete [] pArray_No1;过后我对问题(2)有些自己的理解,不知道是否正确:“pArray_No2指向了数组a首元素的地址”
这个没错,所以pArray_No2储存的就是数组a首元素的地址值,sizeof(pArray_No2)=4那是没错的;
而“a代表的肯定是数组a首元素的地址”这句也没错,但是这里a是数组,数组虽然也算指针,而数组
与指针是有区别的,所以sizeof(a)=16就没错了。然而我的理解只是知其然而不知其所以然,为什么
“数组与指针是有区别的”呢?望爱专细节的朋友帮忙解惑,在下万分感谢!有时候被些问题搞得“食
之无味,夜不能寐”,还好有csdn这个平台,有这么多的好心人帮忙!
< <sizeof(pArray_No2) < <endl //结果为4 同上
< <sizeof(a) < <endl //结果为16 a是个含4个整型的数组,所以4X4=16
< <sizeof(&a[0]) < <endl; //结果为4 &a[0]是个地址,相当于指针,所以也是4
但a的类型为 int* [4],所以大小为4*4 = 16
我这边有篇文章推荐你看下
http://www.vcfans.com/2008/09/c-c-array-of-indicators-and-to-explore-the-deep-differences-between.html
一看我想你就明白了
7.3 指针与数组的对比
C++/C 程序中,指针和数组在不少地方可以相互替换着用,让人产生一种错觉,以
为两者是等价的。
数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。数组名对应着(而
不是指向)一块内存,其地址与容量在生命期内保持不变,只有数组的内容可以改变。
指针可以随时指向任意类型的内存块,它的特征是“可变”,所以我们常用指针来操
作动态内存。指针远比数组灵活,但也更危险。
高质量C++/C 编程指南,v 1.0
2001 Page 46 of 101
下面以字符串为例比较指针与数组的特性。
7.3.1 修改内容
示例7-3-1 中,字符数组a 的容量是6 个字符,其内容为hello\0。a 的内容可以改变,
如a[0]= ‘X’。指针p 指向常量字符串“world”(位于静态存储区,内容为world\0),常
量字符串的内容是不可以被修改的。从语法上看,编译器并不觉得语句p[0]= ‘X’有什么
不妥,但是该语句企图修改常量字符串的内容而导致运行错误。
char a[] = “hello”;
a[0] = ‘X’;
cout << a << endl;
char *p = “world”; // 注意p 指向常量字符串
p[0] = ‘X’; // 编译器不能发现该错误
cout << p << endl;
示例7-3-1 修改数组和指针的内容
7.3.2 内容复制与比较
不能对数组名进行直接复制与比较。示例7-3-2 中,若想把数组a 的内容复制给数
组b,不能用语句 b = a ,否则将产生编译错误。应该用标准库函数strcpy 进行复制。
同理,比较b 和a 的内容是否相同,不能用if(b==a) 来判断,应该用标准库函数strcmp
进行比较。
语句p = a 并不能把a 的内容复制指针p,而是把a 的地址赋给了p。要想复制a
的内容,可以先用库函数malloc 为p 申请一块容量为strlen(a)+1 个字符的内存,再用
strcpy 进行字符串复制。同理,语句if(p==a) 比较的不是内容而是地址,应该用库函
数strcmp 来比较。
// 数组…
char a[] = "hello";
char b[10];
strcpy(b, a); // 不能用 b = a;
if(strcmp(b, a) == 0) // 不能用 if (b == a)
…
// 指针…
int len = strlen(a);
char *p = (char *)malloc(sizeof(char)*(len+1));
strcpy(p,a); // 不要用 p = a;
if(strcmp(p, a) == 0) // 不要用 if (p == a)
…
示例7-3-2 数组和指针的内容复制与比较
高质量C++/C 编程指南,v 1.0
2001 Page 47 of 101
7.3.3 计算内存容量
用运算符sizeof 可以计算出数组的容量(字节数)。示例7-3-3(a)中,sizeof(a)
的值是12(注意别忘了’\0’)。指针p 指向a,但是sizeof(p)的值却是4。这是因为
sizeof(p)得到的是一个指针变量的字节数,相当于sizeof(char*),而不是p 所指的内
存容量。C++/C 语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。
注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。示例
7-3-3(b)中,不论数组a 的容量是多少,sizeof(a)始终等于sizeof(char *)。
char a[] = "hello world";
char *p = a;
cout<< sizeof(a) << endl; // 12 字节
cout<< sizeof(p) << endl; // 4 字节
示例7-3-3(a) 计算数组和指针的内存容量
void Func(char a[100])
{
cout<< sizeof(a) << endl; // 4 字节而不是100 字节
}
示例7-3-3(b) 数组退化为指针
7.4 指针参数是如何传递内存的?
如果函数的参数是一个指针,不要指望用该指针去申请动态内存。示例7-4-1 中,
Test 函数的语句GetMemory(str, 200)并没有使str 获得期望的内存,str 依旧是NULL,
为什么?
void GetMemory(char *p, int num)
{
p = (char *)malloc(sizeof(char) * num);
}
void Test(void)
{
char *str = NULL;
GetMemory(str, 100); // str 仍然为 NULL
strcpy(str, "hello"); // 运行错误
}
示例7-4-1 试图用指针参数申请动态内存
高质量C++/C 编程指南,v 1.0
2001 Page 48 of 101
毛病出在函数GetMemory 中。编译器总是要为函数的每个参数制作临时副本,指针
参数p 的副本是 _p,编译器使 _p = p。如果函数体内的程序修改了_p 的内容,就导致
参数p 的内容作相应的修改。这就是指针可以用作输出参数的原因。在本例中,_p 申请
了新的内存,只是把_p 所指的内存地址改变了,但是p 丝毫未变。所以函数GetMemory
并不能输出任何东西。事实上,每执行一次GetMemory 就会泄露一块内存,因为没有用
free 释放内存。
如果非得要用指针参数去申请内存,那么应该改用“指向指针的指针”,见示例7-4-2。
void GetMemory2(char **p, int num)
{
*p = (char *)malloc(sizeof(char) * num);
}
void Test2(void)
{
char *str = NULL;
GetMemory2(&str, 100); // 注意参数是 &str,而不是str
strcpy(str, "hello");
cout<< str << endl;
free(str);
}
示例7-4-2 用指向指针的指针申请动态内存
由于“指向指针的指针”这个概念不容易理解,我们可以用函数返回值来传递动态
内存。这种方法更加简单,见示例7-4-3。
char *GetMemory3(int num)
{
char *p = (char *)malloc(sizeof(char) * num);
return p;
}
void Test3(void)
{
char *str = NULL;
str = GetMemory3(100);
strcpy(str, "hello");
cout<< str << endl;
free(str);
}
示例7-4-3 用函数返回值来传递动态内存
高质量C++/C 编程指南,v 1.0
2001 Page 49 of 101
用函数返回值来传递动态内存这种方法虽然好用,但是常常有人把return 语句用错
了。这里强调不要用return 语句返回指向“栈内存”的指针,因为该内存在函数结束时
自动消亡,见示例7-4-4。
char *GetString(void)
{
char p[] = "hello world";
return p; // 编译器将提出警告
}
void Test4(void)
{
char *str = NULL;
str = GetString(); // str 的内容是垃圾
cout<< str << endl;
}
示例7-4-4 return 语句返回指向“栈内存”的指针
用调试器逐步跟踪Test4,发现执行str = GetString 语句后str 不再是NULL 指针,
但是str 的内容不是“hello world”而是垃圾。
如果把示例7-4-4 改写成示例7-4-5,会怎么样?
char *GetString2(void)
{
char *p = "hello world";
return p;
}
void Test5(void)
{
char *str = NULL;
str = GetString2();
cout<< str << endl;
}
示例7-4-5 return 语句返回常量字符串
函数Test5 运行虽然不会出错,但是函数GetString2 的设计概念却是错误的。因为
GetString2 内的“hello world”是常量字符串,位于静态存储区,它在程序生命期内
恒定不变。无论什么时候调用GetString2,它返回的始终是同一个“只读”的内存块。
. 在动态运行时,指针保存了某内存的地址(不管是数据块内存还是函数入口地址),数组也是,所以它们的行为是一样的;
. 但在静态编译时,编译器自动为数组标记了其内存块的大小,所以我们可以用sizeof(数组名)取得它的大小。注意在编译时,因为编译器已经知道了sizeof(数组名)的值,所以直接用标记值替换sizeof(数组名),最终效果就是相当于一个常量。一句话,sizeof取得的是数据型的大小(数组是特殊的数据型)。
那么上面的代码就好解析了:cout <<sizeof(pArray_No1) <<endl // 数据型为int *,指针
<<sizeof(pArray_No2) <<endl // 数据型为int *,指针
<<sizeof(a) <<endl // 数据型为int [4],静态数组
<<sizeof(&a[0]) <<endl //数据型为int *,指针 // 为方便理解,多加几行
<<sizeof(a[0]) <<endl //数据型为int,静态数据类型
<<sizeof(&pArray_No2) <<endl //数据型为int**,本质上还是指针
<<sizeof(int) <<endl; //数据型为int,静态数据类型
void FuckRB(char[] szGirlName)
{
// ...
cout<<sizeof(szGirlName); // 数据型为char[],相当于char*,指针
}int main()
{
char name[] = "WuTengLan's daughter";
FuckRB(name);
return 0;
}
函数是在运行时动态调用的,所以在FuchRB()内部看来,szGirlName仅仅是一个指针(char *)而已。因为编译器有记录的标识符是name,并不是szGirlName
*pArray_No2 这也是个指向INT类型的<指针>
a[]={1,2,3,4} 这是有4个INT类型元素的数组指针的大小在32机里就是4个Byte, 不管它指向什么类型的变量
sizeof只是取变量的大小.
sizeof( pArray_No1 ) 变量pArray_No1为指针, 所以它的大小当然是4个Byte
sizeof( a ) a是个数组, 大小当然为4Byte * 4 = 16Byte
sizeof( &a[ 0 ] ) 这是取a数组第一个元素的地址, 那当然是个指针了, 就是4个Byte这很好理解的.
如果是数组,则返回数组的大小,以字节为单位
例如:
int *p;
char *pp;
double *ppp;
sizeof(p)=sizeof(pp)=sizeof(ppp)=4;//32位系统
int p[10];
char pp[10];
double pp[10];
sizeof的结果为 40=10*sizeof(int),10=10*sizeof(char),80=10*sizeof(double)
譬如int[10],就是一个数组类型的object,size是10*sizeof(int),它有一个强制转换符可以将这个object的指针转换成int*。
本质上数组和指针压根不是一个东西,此流毒我认为始作俑者是谭浩强。
pArray_No2=a;
那么pArray_No2与a的类型应该是一样的,但是sizeof(pArray_No2)=4;sizeof(a)=16;这里为什么又不一致了呢?
所以你的回答是片面的!还是谢谢了,大家共同进步!
CString就是能当成LPCTSTR用,于是乎种种迹象表明CString就是LPCTSTR!这能说通?
数组就是数组,指针就是指针,完全两种东西!
正确的是:数组的名,在某些情况下可以当成指针使用。仅此而已,再往前进一步就变成了谬误。
char a[10];
int b[sizeof(a)];想想看,然后再考虑考虑编译器是否将数组和指针区别对待了?
The sizeof keyword gives the amount of storage, in bytes, associated with a
variable or a type (including aggregate types).
This keyword returns a value of type size_t.
其返回值类型为size_t,在头文件stddef.h中定义。这是一个依赖于编译系统的值,一
般定义为
typedef unsigned int size_t;
sizeof获取的类型的大小,楼主只需要理解编译期和运行期的区别就行了,就是静态的数组的大小在编译期就决定了,所以sizeof获取的是数组的大小,而指针动态开辟内存,sizeof不能获取它的开辟的内存的大小,它只能指针在该编译器的编译期的大小,在win32平台上无论什么指针的大小都是4个指针。
int b[sizeof(a)]=int b[10]
我弱弱的感觉应该能编译通过!呵呵!
codewarrior兄这么爱抓细节,我喜欢!
言归正传,你的讲解确实很独到,以致我昨天回复的时候放到最后却因为连续回复3次而不能回复了,所以今天补上!codewarrior与你的回答让我很受用,感觉茅塞顿开!