struct vs array

C里面array是一个比较特殊的类型, 例如char a[10]= "abcdef"; 在编译时, a会替换成存储实际内容的内存首地址. 所以没有地方存储变量a.
因此使用a和&a 都可以打印a的地址.
如 : 
[root@db-172-16-3-150 zzz]# cat d.c
#include <stdio.h>

char a[10] = "abc";

int main() {
  fprintf(stdout,"addr a:%p, addr &a:%p\n", a, &a);
  return 0;
}
结果 : 
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g ./d.c -o d && ./d
addr a:0x6008c4, addr &a:0x6008c4


struct 定义的变量, 变量就是变量, 它不是一个指针. 这点和array不同. 例如 : 
[root@db-172-16-3-150 zzz]# cat d.c
#include <stdio.h>

struct fish {
  int a;
  float c;
  char b[10];
};

int main() {
  struct fish f1 = {1, 9.9, "abcd"};
  fprintf(stdout,"addr f1:%p, addr &f1:%p\n", f1, &f1);
  return 0;
}
报错, 也就是说f1 是个变量, 要取地址需要使用&, 这点和其他的变量相同 : 
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g ./d.c -o d && ./d
cc1: warnings being treated as errors
./d.c: In function ‘main’:
./d.c:11: warning: format ‘%p’ expects type ‘void *’, but argument 3 has type ‘struct fish’

修改后 :
[root@db-172-16-3-150 zzz]# cat d.c
#include <stdio.h>

struct fish {
  int a;
  float c;
  char b[10];
};

int i;

int main() {
  struct fish f1 = {1, 9.9, "abcd"};
  i = 10;
  fprintf(stdout,"addr &i:%p, addr &f1:%p\n", &i, &f1);
  return 0;
}
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g ./d.c -o d && ./d
addr &i:0x600934, addr &f1:0x7fffdd6bec90


虽然使用%p 打印的 a或者&a 内容是一致的, 但是a 和 &a 是有区别的. 可以通过测试来看一看.
a[1] 等同于 *(a+1) , 这里 a+1 用到了指针的地址运算, 即a的地址加上1个数组中的元素占用的空间. 如int a[], 一个元素占用4字节. char a[]中一个元素占用1字节. 如下 : 

[root@db-172-16-3-150 zzz]# cat d.c
#include <stdio.h>

char a[10] = "abc";
int b[10] = {1,2,3,4,5};

int main() {
  fprintf(stdout,"addr a:%p, addr a[1]:%p, addr a+1:%p\n", a, &(a[1]), &(*(a+1)));  // &(*(a+1)) 替换成 (a+1) 是一样的
  fprintf(stdout,"addr b:%p, addr b[1]:%p, addr b+1:%p\n", b, &(b[1]), &(*(b+1)));  // &(*(b+1)) 替换成 (b+1) 是一样的
  return 0;
}
结果 : 
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g ./d.c -o d && ./d
addr a:0x600940, addr a[1]:0x600941, addr a+1:0x600941
addr b:0x600960, addr b[1]:0x600964, addr b+1:0x600964


既然 数组名 a 是指针, 那&a 是什么呢? 能不能像a这样做指针的地址运算呢?
可以, 但是已经和a+1 得到的结果不一样了, 那么(&a)+1 会是什么意思? 结果是什么呢?
&a 表示存储a这个数组的首内存地址, 所以(&a) +1 则表示下一个和a数组占用一样大小空间的数组的内存首地址.
换句话说a表示的是char类型的指针 , 而&a 表示的是char a[10]这个数组类型的指针 . 
因为C是强类型语言, 所以加减结果必然与类型有关. 
来看个例子 : 

[root@db-172-16-3-150 zzz]# cat d.c
#include <stdio.h>

char a[10] = "abc";
int b[10] = {1,2,3,4,5};

int main() {
  fprintf(stdout,"sizeof(a):%lu, sizeof(b):%lu\n", sizeof(a), sizeof(b));
  fprintf(stdout,"addr a:%p, addr a[1]:%p, addr (&a)+1:%p\n", a, &(a[1]), ((&a)+1));
  fprintf(stdout,"addr b:%p, addr b[1]:%p, addr (&b)+1:%p\n", b, &(b[1]), ((&b)+1));
  return 0;
}
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g ./d.c -o d && ./d
sizeof(a):10, sizeof(b):40
addr a:0x6009a0, addr a[1]:0x6009a1, addr (&a)+1:0x6009aa  // 结果表明 0x6009aa - 0x6009a0 刚好等于10字节, a[10]的大小.
addr b:0x6009c0, addr b[1]:0x6009c4, addr (&b)+1:0x6009e8  // 结果表明 0x6009e8 - 0x6009c0 刚好等于40字节, b[10]的大小.


前面我们看到array可以用[0],[1]来取数组中的元素. 那么struct用什么来取呢? 用点. 不能用[]这种方式.
来看个例子 : 

[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g ./d.c -o d && ./d
a[0]:a, a[1]:b
b[0]:1, b[1]:2
f1.age:20, f1.weight:60.500000, f1.name:linux
[root@db-172-16-3-150 zzz]# cat d.c
#include <stdio.h>

char a[10] = "abc";
int b[10] = {1,2,3,4,5};
struct fish {
  int age;
  float weight;
  char name[10];
};

int main() {
  struct fish f1 = {20, 60.5, "linux"};
  fprintf(stdout,"a[0]:%c, a[1]:%c\n", a[0], *(a+1));
  fprintf(stdout,"b[0]:%i, b[1]:%i\n", b[0], *(b+1));
  fprintf(stdout,"f1.age:%i, f1.weight:%f, f1.name:%s\n", f1.age, f1.weight, f1.name);
  return 0;
}
结果 : 
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g ./d.c -o d && ./d
a[0]:a, a[1]:b
b[0]:1, b[1]:2
f1.age:20, f1.weight:60.500000, f1.name:linux

但是需要注意的是, struct中, 使用(.点)来引用元素的时候和array使用[]来应用元素的区别.
数组中 , a[1] = *(a+1) 是指的内容(char). 而不是指针(pointer).
struct 中 f1.? 真实反映这个元素的内容 (int, char, 或char [])  例如 : 

[root@db-172-16-3-150 zzz]# cat d.c
#include <stdio.h>

struct fish {
  int age;
  float weight;
  char name[10];
};

int main() {
  struct fish f1 = {20, 60.5, "linux"};
  fprintf(stdout,"f1.age:%i, f1.weight:%f, f1.name:%s ,f1.name[1]:%c, (f1.name)[1]:%c, *((f1.name)+1):%c\n", f1.age, f1.weight, f1.name, f1.name[1], (f1.name)[1], *((f1.name)+1));
  return 0;
}
结果 : 
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g ./d.c -o d && ./d
f1.age:20, f1.weight:60.500000, f1.name:linux ,f1.name[1]:i, (f1.name)[1]:i, *((f1.name)+1):i

所以 f1.name[1],  (f1.name)[1],  *((f1.name)+1) 这三种写法是一样的.

在初始化完变量后,  struct 和 array 一样, 里面的元素都是连续存储的 . 
例如 : 

[root@db-172-16-3-150 zzz]# cat d.c
#include <stdio.h>

char a[] = "abcdef";
struct fish {
  int age;
  float weight;
  char name[10];
};

int main() {
  struct fish f1 = {20, 60.5, "linux"};
  fprintf(stdout,"sizeof(char):%lu, sizeof(int):%lu, sizeof(float):%lu, sizeof(char [10]):%lu\n", sizeof(char), sizeof(int), sizeof(float), sizeof(char [10]));
  fprintf(stdout,"sizeof(f1.age):%lu, sizeof(f1.weight):%lu, sizeof(f1.name):%lu\n", sizeof(f1.age), sizeof(f1.weight), sizeof(f1.name));
  fprintf(stdout,"sizeof(a):%lu, addr a:%p, addr a[0]:%p, addr a[1]:%p, addr a[2]:%p\n", sizeof(a), a, a, a+1, a+2);
  fprintf(stdout,"sizeof(f1):%lu, addr &f:%p, addr f1.age:%p, addr f1.weight:%p, addr f1.name:%p\n", sizeof(f1), &f1, &(f1.age), &(f1.weight), &(f1.name));
  return 0;
}

结果 : 
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g ./d.c -o d && ./d
sizeof(char):1, sizeof(int):4, sizeof(float):4, sizeof(char [10]):10
sizeof(f1.age):4, sizeof(f1.weight):4, sizeof(f1.name):10
sizeof(a):7, addr a:0x600aac, addr a[0]:0x600aac, addr a[1]:0x600aad, addr a[2]:0x600aae
sizeof(f1):20, addr &f:0x7fff0c25ec30, addr f1.age:0x7fff0c25ec30, addr f1.weight:0x7fff0c25ec34, addr f1.name:0x7fff0c25ec38


在赋值方面, array 和 struct 也有所不同. 例如
[root@db-172-16-3-150 zzz]# cat d.c
#include <stdio.h>
#include <string.h>

char a[] = "abcdef";
struct fish {
  int age;
  float weight;
  char name[10];
  char * nick;
};

int main() {
  struct fish f1 = {20, 60.5, "linux", "unix"};
  // 结构可以通过拷贝来赋值 , 注意每个元素都会拷贝一份, 对于指针类型的元素,  拷贝的则是指针(所以f2 和f1 的nick 将指向同一个区域.)
  struct fish f2 = f1;
  char b[10];
  *(b) = a[0];
  *(b+1) = a[1];
  *(b+2) = *(a+2);
  *(b+3) = a[3];
  b[4] = a[4];
  b[5] = a[5];
  // 数组不能简单的用等于来直接拷贝. 以下三种赋值都是错误的.
  // 再一次说明了array b这个b已经在编译时被替换为地址, 而struct fish f2它是个变量名, 才能够通过此方式赋值.
  // b = a;
  // *b = *a;
  // *b = a;
  fprintf(stdout, "a:%s, b:%s\n", a, b);
  fprintf(stdout, "addr f1:%p, addr f2:%p\n", &f1, &f2);
  fprintf(stdout, "&(f1.age):%p, &(f1.weight):%p, &(f1.name):%p, &(f1.nick):%p, f1.name:%p, f1.nick:%p\n", &(f1.age), &(f1.weight), &(f1.name), &(f1.nick), f1.name, f1.nick);
  fprintf(stdout, "&(f2.age):%p, &(f2.weight):%p, &(f2.name):%p, &(f2.nick):%p, f2.name:%p, f2.nick:%p\n", &(f2.age), &(f2.weight), &(f2.name), &(f2.nick), f2.name, f2.nick);
  return 0;
}

结果 : 
f1.nick和f2.nick 打印%p 结果一致, 说明f1.nick和f2.nick指向同一个字符串.
struct vs array - 德哥@Digoal - The Heart,The World.

[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g ./d.c -o d && ./d
a:abcdef, b:abcdef
addr f1:0x7fff78ff9af0, addr f2:0x7fff78ff9ad0
&(f1.age):0x7fff78ff9af0, &(f1.weight):0x7fff78ff9af4, &(f1.name):0x7fff78ff9af8, &(f1.nick):0x7fff78ff9b08, f1.name:0x7fff78ff9af8, f1.nick:0x400748
&(f2.age):0x7fff78ff9ad0, &(f2.weight):0x7fff78ff9ad4, &(f2.name):0x7fff78ff9ad8, &(f2.nick):0x7fff78ff9ae8, f2.name:0x7fff78ff9ad8, f2.nick:0x400748

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值