在C中, array变量和指针极其相似.
指针加减运算, 首先需要知道指针类型, 类型占用的字节数, 如int *的指针, 加1 则表示地址加4字节(假设32位的机器int占4字节);
如果是char * 的指针, 指针变量加1则表示地址加1字节(char 占1个字节).
例子1 :
#include <stdio.h>
#include <stdlib.h>
int main() {
char a[10] = "abcdefg";
printf("a[0]:%i\n",a[0]);
printf("a[0]:%c\n",a[0]);
printf("a:%s\n",&a[0]);
printf("a:%s\n",a);
printf("a<<1:%s\n",&a[1]);
printf("addr(a):%p\n",a);
printf("addr(a[0]):%p\n",&a[0]);
return 0;
}
gcc -O3 -Wall -Wextra -Werror -g ./l.c -o l && ./l
a[0]:97
a[0]:a
a:abcdefg
a:abcdefg
a<<1:bcdefg
addr(a):0x7fff7f92b310
addr(a[0]):0x7fff7f92b310
从地址上看array变量应该在stack里面, 属于高位地址. 因为array定义后无法改变它指向的地址. 用于指向array创建时分配的空间的首地址.
例子2 :
#include <stdio.h>
#include <stdlib.h>
int main() {
char *a = "abcdefg";
printf("a[0]:%i\n",a[0]);
printf("a[0]:%c\n",a[0]);
printf("a:%s\n",&a[0]);
printf("a:%s\n",a);
printf("a<<1:%s\n",&a[1]);
printf("addr(a):%p\n",a);
printf("addr(a[0]):%p\n",&a[0]);
return 0;
}
gcc -O3 -Wall -Wextra -Werror -g ./l.c -o l && ./l
a[0]:97
a[0]:a
a:abcdefg
a:abcdefg
a<<1:bcdefg
addr(a):0x40063a
addr(a[0]):0x40063a
从地址上看指针变量应该在constants里面, 属于低位地址. 因为指针指向的是"abcdefg"这个常量的首地址, 字符串是放在内存的constants区域的.
constants区域不能改变.
另外指针加减算法得到的结果还是指针, 但是如果要得到结果指向的内容可以使用*, 或者[]. 如下 :
printf 函数, 在打印%s时, 对应的参数必须是char *. 在打印%c 和 %i 时对应的参数必须是int. 打印%p时对应的参数必须是指针.
另外需要注意的几点 :
1. 调用函数时, 传递的是值, 而不是传入的变量本身, 所以如果要修改传入的变量的值, 使用指针传递是比较好的方法, 因为拷贝指针的值指向的是想修改的变量地址.
2. 通过指针修改变量的值, 可使用* 或者[]. 如上图.
例如 :
#include <stdio.h>
#include <stdlib.h>
char a[] = "abc";
void exchange1(char * i) {
char x;
x = i[0];
i[0] = i[2];
i[2] = x;
}
void exchange2(char * i) {
char x;
x = *i;
*i = *(i+2);
*(i+2) = x;
}
int main() {
printf("old a:%s\n", a);
exchange1(a);
printf("new1 a:%s\n", a);
exchange2(a);
printf("new2 a:%s\n", a);
return 0;
}
gcc -O3 -Wall -Wextra -Werror -g ./l.c -o l && ./l
old a:abc
new1 a:cba
new2 a:abc
3. 由于char * a = "ABC" 这种方式定义的指针, 字符串是存储在constants区域的, 无法修改. 所以一般这种定义可以改为const char * a = "ABC"/
那么在代码中如果出现a[0]="O"; 这种语句时编译器会报错. 更容易理解.
从内存地址可以看出加了const和未加const定义的变量, 他们存放的内存区域是不一样的.
#include <stdio.h>
#include <stdlib.h>
const char a[] = "abc";
const char b[] = "abc";
char c[] = "abc";
char d[] = "abc";
char *e = "abc";
char *f = "abc";
int main() {
printf("addr a:%p\n", a);
printf("addr b:%p\n", b);
printf("addr c:%p\n", c);
printf("addr d:%p\n", d);
printf("addr e:%p\n", e);
printf("addr f:%p\n", f);
return 0;
}
gcc -O3 -Wall -Wextra -Werror -g ./l.c -o l && ./l
addr a:0x40065e
addr b:0x400662
addr c:0x600910
addr d:0x600914
addr e:0x40065a
addr f:0x40065a
同时你会发现constant "abc". 只放了一份. e和f指向同一地址.
4. Q: I still don’t understand why an array variable isn’t stored in memory. If it exists, surely it lives somewhere?
A: When the program is compiled, all the references to array variables are replaced with the addresses of the array.
So the truth is that the array variable won’t exist in the final executable. That’s OK because the array variable will never be needed to point anywhere else.
Q: If I set a new array to a string literal, will the program really copy the contents each time?
A: It’s down to the compiler. The final machine code will either copy the bytes of the string literal to the array, or else the program will simply set the values of each character every time it reaches the declaration.
Q: You keep saying “declaration.” What does that mean?
A: A declaration is a piece of code that declares that something (a variable, a function) exists. A definition is a piece of code that says what something is. If you declare a variable and set it to a value (e.g., int x = 4;), then the code is both a declaration and a definition.