共有回帖数 0 个
-
本文代码编写编译运行的环境:[Mac-10.7.1 Lion Intel-based]
Q: 有的时候总是发现一个数组的字符串可以修改,但是如果使用字符串字面量就不能修改,这是为什么? [cpp] view plaincopy
#include stdio.h
int main()
{
char buf[] = "hello";
char *str = "hello";
buf[0] = 'a';
str[0] = 'a';
return 0;
}

Q: 那么怎么证明char buf[] = "hello"; 中buf保存的数据hello在栈中呢? A: 使用gcc -S char_string.c得到它的汇编形式: [cpp] view plaincopy
movb L_.str(%rip), %al
movb %al, -14(%rbp)
movb L_.str+1(%rip), %al
movb %al, -13(%rbp)
movb L_.str+2(%rip), %al
movb %al, -12(%rbp)
movb L_.str+3(%rip), %al
movb %al, -11(%rbp)
movb L_.str+4(%rip), %al
movb %al, -10(%rbp)
movb L_.str+5(%rip), %al
movb %al, -9(%rbp)
leaq L_.str(%rip), %rax
movq %rax, -24(%rbp)
movb $97, -14(%rbp)
其中L_.str为:[cpp] view plaincopy
L_.str:
.asciz "hello" 可以看到,上面的汇编代码中的%rbp即为和堆栈基址相对应的寄存器。
Q: 常常看到,如果arr是个数组,arr和*(arr + i)是等同的, 这里的i可以为负数吗? A: 是的。数组就是个数据块,至于是取arr更高地址还是更低地址的数据,这有程序员决定。当然,arr表示数组的初始地址,取比它更低的地址可能不是程序员的本来意图,小心为之。 [cpp] view plaincopy
#include stdio.h
#define PRINT_D(intValue) printf(#intValue" is %dn", (intValue));
int main()
{
int arr[] = {1, 2};
int n = 3;
PRINT_D(arr[0])
PRINT_D(arr[-1])
return 0;
} 编译运行:

[cpp] view plaincopy
#include stdio.h
#define PRINT_P(pointer) printf("%10s is %pn", #pointer, (pointer));
int main (int argc, const char * argv[])
{
int arr[2][3] = {1, 2, 3, 4, 5, 6};
PRINT_P(arr)
PRINT_P(&arr)
PRINT_P(arr[0])
PRINT_P(&arr[0])
PRINT_P(arr[1])
PRINT_P(&arr[1])
return 0;
}

#include stdio.h
#define PRINT_P(pointer) printf("%10s is %pn", #pointer, (pointer));
#define PRINT_D(intValue) printf(#intValue" is %dn", (intValue));
void print_arr(int *arr, int size)
{
int i = 0;
for(; i size; ++i)
PRINT_D(arr)
}
int main (int argc, const char * argv[])
{
int arr[] = {1, 2, 3};
print_arr(arr, sizeof(arr) / sizeof(arr[0]));
return 0;
}
因为数组元素是整形的,所以数组地址为整形指针,即为上面的int *, 还有个参数size表示数组的大小。
Q: 既然数组的个数可以用sizeof(arr) / sizeof(arr[0])来表示,那么参数size不就是不必要的吗,print_arr函数里面直接用这个表达式不就可以得到数组的大小了么? A: 测试下。 [cpp] view plaincopy
#include stdio.h
#define PRINT_P(pointer) printf("%10s is %pn", #pointer, (pointer));
#define PRINT_D(intValue) printf(#intValue" is %dn", (intValue));
void print_arr(int *arr)
{
int i = 0;
for(; i sizeof(arr) / sizeof(arr[0]); ++i)
PRINT_D(arr)
}
int main (int argc, const char * argv[])
{
int arr[] = {1, 2, 3};
print_arr(arr);
return 0;
}

0x0000000100000ded print_arr+29: lea 0xa4(%rip),%rdi # 0x100000e98
0x0000000100000df4 print_arr+36: movslq -0xc(%rbp),%rax
0x0000000100000df8 print_arr+40: mov -0x8(%rbp),%rcx
0x0000000100000dfc print_arr+44: mov (%rcx,%rax,4),%esi
0x0000000100000dff print_arr+47: mov $0x0,%al
0x0000000100000e01 print_arr+49: callq 0x100000e6e dyld_stub_printf
0x0000000100000e06 print_arr+54: mov %eax,-0x10(%rbp)
0x0000000100000e09 print_arr+57: mov -0xc(%rbp),%eax
0x0000000100000e0c print_arr+60: add $0x1,%eax
0x0000000100000e0f print_arr+63: mov %eax,-0xc(%rbp)
0x0000000100000e12 print_arr+66: jmp 0x100000de3 print_arr+19
0x0000000100000e14 print_arr+68: add $0x10,%rsp
0x0000000100000e18 print_arr+72: pop %rbp
0x0000000100000e19 print_arr+73: retq
可以看到第七行位置的cmp指令和第八行的jae指令,表示如果循环变量i大于或者等于2,那么跳到结束位置。也就是说,这个函数里面,把arr数组大小 看成了2, 这是为什么呢?这是因为编译器编译print_arr函数代码时,根本不知道传入int * arr参数的到底是个数组还是指针,所以sizeof(arr) / sizeof(arr[0])得到的是sizeof(int *) / sizeof(int)的值(笔者平台得到的是2)。其实这也是数组名作为参数的一个可能引发错误的地方。
Q: 那么如果把参数形式int *arr改为int arr[]就能将arr当成数组了,代码就会正确执行? A: 很可惜,c语言的语法决定了任何代码都会编译成确定指令的东西,和上面说的一样,print_arr依然不知道外部传入参数arr的数组或者指针到底有多大,sizeof(arr) / sizeof(arr[0])最终又被得到一个诡异的数据。
Q: 那该怎么办? A: 就另外传入一个参数为传入数组的元素个数即可。
Q: 关于二维数组,经常看到一些很诡异的样式,到底怎么很好地理解? A: 形如如下代码: [cpp] view plaincopy
#include stdio.h
#define PRINT_P(pointer) printf("%10s is %pn", #pointer, (pointer));
#define PRINT_D(intValue) printf(#intValue" is %dn", (intValue));
int main (int argc, const char * argv[])
{
int arr[] = {1, 2};
int (*p_arr)[2] = &arr;
PRINT_D(**p_arr)
return 0;
}

#include stdio.h
#define PRINT_P(pointer) printf("%10s is %pn", #pointer, (pointer));
#define PRINT_D(intValue) printf(#intValue" is %dn", (intValue));
int main (int argc, const char * argv[])
{
int arr[][2] = {{1, 2}, {3, 4}}; int (*p_arr)[2] = &arr[0];
PRINT_D(p_arr[1][1])
p_arr = &arr[1];
PRINT_D(p_arr[0][1])
return 0;
}



#include stdio.h
int (*func1)(int *arg);
int (*func2)(int *arg);
int (*func3)(int *arg);
int main (int argc, const char * argv[])
{
int (*p[3])(int *arg) = {func1, func2, func3};
return 0;
}
第二个:*func表示func是一个指针,后面的int *p表示,它是一个函数指针,参数为int *p, 左侧一个星号,表示返回值是个指针,右侧[3]表示返回值是个3个元素的数组,每个元素都是指针,最左侧的int表示返回值的数组元素为整形。总 结下:func是个函数指针,参数为int *p, 返回值为包含5个元素的数组,且为指针。 第三个: 类似第一个,不过func多了一个指针类型。总结:func是一个指针,它指向一个数组,数组元素个数为3,每个元素都是一个函数指针,函数指针参数为int *p, 返回值为int.
#include stdio.h
int main()
{
char buf[] = "hello";
char *str = "hello";
buf[0] = 'a';
str[0] = 'a';
return 0;
}
这个代码 发现一个有趣的现象
cl编译器对于这个代码可以编译运行成功
详细讨论见 htt放和谐p://放和谐topic.放和谐csdn.ne放和谐t/t/20060放和谐223/00/45放和谐71769.html
楼主 2016-03-31 14:39 回复
Copyright © 2010~2015 直线网 版权所有,All Rights Reserved.沪ICP备10039589号
意见反馈 |
关于直线 |
版权声明 |
会员须知