转自:http://www.itxuexi.com/tech/kaifa/cc/9241250231405.html
c语言中指针和数组在编译时的区别 例如:int a[10]和int *b,a[5]和*(b+5) 在编译的时候区别是什么? 经过反复的查资料和请教他人,最后在《c专家编程》里找到了很好的答案。
1。编译器对数组名和指针变量的处理方式
编译器在编译时会产生一个符号表,记录了符号名和它的地址。对于指针变量,这显然很好理解。而数组名就不那么明显了,它仅仅是一个符号而已,何来地址?编译器是这样处理的,它记录了array[0]的地址;这和我们通常的理解也是一样的。
2。带下标形式的数组和指针寻址方式
(1)数组情形
char a[9]="abcdefgh";
...
c=a[i];
在编译期,会在符号表中创建这样一条记录:
name:a address:9980
要获取a[i]的值分两个步骤:
step 1:取得i的值并和9980相加
step 2:在内存地址(9980+i)处取其内容
(2)指针情形
char* p="abcdefgh";
...
c=p[i];
在编译期,会在符号表中创建这样一条记录:
name:p address:4624
要获取p[i]的值分三个步骤:
step 1:在内存地址4624处取其内容,比如说“5081”
step 2:取得i的值并和5081相加
step 3:在内存地址(5081+i)取其内容
来自:http://blog.csdn.net/hairetz/archive/2009/04/30/4141043.aspx
一、预备知识—程序的内存分配
一个由C/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其
操作方式类似于数据结构中的栈。
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回
收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的
全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另
一块区域。 - 程序结束后由系统释放。
4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放
5、程序代码区—存放函数体的二进制代码。
二、例子程序
这是一个前辈写的,非常详细
//main.cpp
int a = 0; 全局初始化区
char *p1; 全局未初始化区
main()
{
int b; 栈
char s[] = "abc"; 栈
char *p2; 栈
char *p3 = "123456"; 123456/0在常量区,p3在栈上。
static int c =0; 全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456"); 123456/0放在常量区,编译器可能会将它与p3所指向的"123456"
优化成一个地方。
}
2.6存取效率的比较
char s1[] = "aaaaaaaaaaaaaaa";
char *s2 = "bbbbbbbbbbbbbbbbb";
aaaaaaaaaaa是在运行时刻赋值的;
而bbbbbbbbbbb是在编译时就确定的;
但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。
比如:
#include
void main()
{
char a = 1;
char c[] = "1234567890";
char *p ="1234567890";
a = c[1];
a = p[1];
return;
}
对应的汇编代码
10: a = c[1];
00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh]
0040106A 88 4D FC mov byte ptr [ebp-4],cl
11: a = p[1];
0040106D 8B 55 EC mov edx,dword ptr [ebp-14h]
00401070 8A 42 01 mov al,byte ptr [edx+1]
00401073 88 45 FC mov byte ptr [ebp-4],al
第一种在读取时直接就把字符串中的元素读到寄存器cl中,而第二种则要先把指针值读到
edx中,再根据edx读取字符,显然慢了。
来自:http://www.diybl.com/course/3_program/c++/cppsl/2008611/124612.html
是常量的情况:
把"abc"赋给一个字符指针变量时,如char* ptr = "abc";因为定义的是一个普通指针,并没有定义空间来存放"abc",所以编译器得帮找地方来放"abc",显然,把这里的"abc"当成常量并把它放到程序的常量区是编译器最合适的选择。所以尽管ptr的类型不是const char*,并且ptr[0] = 'x';也能编译通过,但是执行ptr[0] = 'x';就会发生运行时异常,因为这个语句试图去修改程序常量区中的东西。记得哪本书中曾经说过char* ptr = "abc";这种写法原来在c++标准中是不允许的,但是因为这种写法在c中实在是太多了,为了兼容c,不允许也得允许。虽然允许,但是建议的写法应该是const char* ptr = "abc";这样如果后面写ptr[0] = 'x'的话编译器就不会让它编译通过,也就避免了上面说的运行时异常。又扩展一下,如果char* ptr = "abc";写在函数体内,那么虽然这里的"abc/0"被放在常量区中,但是ptr本身只是一个普通的指针变量,所以ptr是被放在栈上的,只不过是它所指向的东西被放在常量区罢了。
来自:http://bbs.chinaunix.net/viewthread.php?tid=979141
回复 #1 specter117 的帖子
(1)对于顺序访问的而言,数组比链表效率高。
(2)对于数组,间接访问(指数组名+下标)绝不比指针访问的效率高。
比如:
int i;
int b[100];
数组访问;
for(i = 0; i < 100; i++)
{
b = 0;
}
指针访问:
int *p = b;
for(i = 0; i < 100; i++)
{
*p++ = 0;
}
数组访问时,b等价于*(b + i) =*( (char *)b + i * sizeof(int) )
指针访问时,*p++等价于*(p + 1) = *((char *)p + 1 * sizeof(int))
由于sizeof是在编译时确定的,所以
b = *((char *) b + 4 * i)
而
*p++ = *((char *)p + 1)
间接访问有乘法运算,而指针访问只有加法运算,所以在这里,间接访问没有指针访问效率高。