long blogs

进一步有进一步惊喜


  • Home
  • Archive
  • Tags
  •  

© 2025 long

Theme Typography by Makito

Proudly published with Hexo

C-内存和类型

Posted at 2020-09-29 C 内存 指针 

C内存和类型

测试源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
void *vp = calloc(4,4);

int *int_arr = vp;
for (int i = 0; i < 4; ++i){
printf("int array[%d] => %d\n", i, int_arr[i]);
int_arr[i] = i;
}
for (int i = 0; i < 4; ++i){
printf("int array[%d] => %d\n", i, int_arr[i]);
}

char *char_arr = (char *)vp;
for (int i = 0; i < 16; ++i) {
char_arr[i] = 'a' + i;
}
char_arr[15] = '\0';
printf("char_arr = %s\n", char_arr);

memset(vp,0,16);

memset(vp, 12, 1);
strcpy(vp+4,"Tom Jerry");

struct person {
int32_t age;
char name[12];
} *person_ptr;

person_ptr = vp;
printf("person age:%d, name : %s\n",person_ptr->age, person_ptr->name);

memset(vp+4,0,12);
strcpy(vp+4, "man");
strcpy(vp + 4 + 6,"fat");

struct annimal {
int32_t type;
char type_name[6];
char description[6];
} *annimal_ptr;
annimal_ptr = (struct annimal *)person_ptr;
printf("annimal type: %d, type_name: %s, description: %s\n",annimal_ptr->type, annimal_ptr->type_name, annimal_ptr->description);
free(vp);

输出

1
2
3
4
5
6
7
8
9
10
11
int array[0] => 0
int array[1] => 0
int array[2] => 0
int array[3] => 0
int array[0] => 0
int array[1] => 1
int array[2] => 2
int array[3] => 3
char_arr = abcdefghijklmno
person age:12, name : Tom Jerry
annimal type: 12, type_name: man, description: fat

分析

关于变量类型和内存。申请了4×4字节的内存,内存是与变量无关的,初始化时的内存值为。

1
00 00 00 00   00 00 00 00   00 00 00 00   00 00 00 00   │ ················ │
16字节内存作为整型数组使用

执行到下边的代码之后的内存。

1
2
3
4
5
int *int_arr = vp;
for (int i = 0; i < 4; ++i){
printf("int array[%d] => %d\n", i, int_arr[i]);
int_arr[i] = i;
}

memory:

1
00 00 00 00   01 00 00 00   02 00 00 00   03 00 00 00   │ ················ │

一个int类型大小为4个字节,所以16字节可以转成大小为4的整型数组。

16字节内存作为字符串数组使用

执行到下面的代码,内存变化为

1
2
3
4
5
char *char_arr = (char *)vp;
for (int i = 0; i < 16; ++i) {
char_arr[i] = 'a' + i;
}
char_arr[15] = '\0';

memory:

1
65 66 67 68   69 6a 6b 6c   6d 6e 6f 00   │ abcdefghijklmno· │

一个char类型占用1个字节,16个字节可以放16个字符。

16字节作为结构体变量使用

执行到下面的代码,

1
2
3
memset(vp,0,16);
memset(vp, 12, 1);
strcpy(vp+4,"Tom Jerry");

memory:

1
0c 00 00 00   54 6f 6d 20   4a 65 72 72   79 00 00 00   │ ····Tom Jerry··· │

执行下面的代码

1
2
3
4
5
6
7
struct person {
int32_t age;
char name[12];
} *person_ptr;

person_ptr = vp;
printf("person age:%d, name : %s\n",person_ptr->age, person_ptr->name);

输出

1
person age:12, name : Tom Jerry

16字节的内存被person结构体使用了。

结构体间强转

执行到以下代码

1
2
3
4
5
6
7
8
9
10
11
12
memset(vp+4,0,12);
strcpy(vp+4, "man");
strcpy(vp + 4 + 6,"fat");

struct annimal {
int32_t type;
char type_name[6];
char description[6];
} *annimal_ptr;

annimal_ptr = (struct annimal *)person_ptr;
printf("annimal type: %d, type_name: %s, description: %s\n",annimal_ptr->type, annimal_ptr->type_name, annimal_ptr->description);

memory:

1
0c 00 00 00   6d 61 6e 00   00 00 66 61   74 00 00 00   │ ····man···fat··· │

输出

1
annimal type: 12, type_name: man, description: fat

总结

对于申请的内存得到的内存是无类型的,谁都可以使用。变量类型的作用是用来确定内存的边界。
int类型大小为4个字节,所以会以4个字节为单位进行切割。
char 类型大小为1个字节,以1个字节为单位对16字节的数据进行切割。
person结构体,切割成两个部分。前4个字节作为整型age,后12字节作为char数组name。
annimal结构体,将16字节切割给 type、type_name, description。

扩展-数组

多维静态数组

静态数组int map[2][3] = {{1,2,3},{4,5,6}};在内存的布局如下,前4×6 = 24个字节分别对应map中的值。根据列的长度得出行的个数。列的大小为4×3 = 12,可以将24分成2个。

1
2
01 00 00 00   02 00 00 00   03 00 00 00   04 00 00 00   │ ················ │
05 00 00 00 06 00 00 00 00 b5 e9 21 50 1e 21 4e │ ···········!P·!N │

静态数组:int map2[3][2] = {{1,2},{3,4},{5,6}};内存布局如下。和上面的map变量内存布局一致。不同的是解析方法。

1
2
01 00 00 00   02 00 00 00   03 00 00 00   04 00 00 00   │ ················ │
05 00 00 00 06 00 00 00 00 2a 5b 24 65 cb 71 c8 │ ·········*[$e·q· │

静态数组: int map3[3][2][2] = {{{1,2},{3,4}},{{5,6},{7,8}},{{9,10},{11,12}}}; 内存布局如下,切割方法,最小单位为2×4字节。map3[0][0][0] => 1。

1
2
3
01 00 00 00   02 00 00 00   03 00 00 00   04 00 00 00   │ ················ │
05 00 00 00 06 00 00 00 07 00 00 00 08 00 00 00 │ ················ │
09 00 00 00 0a 00 00 00 0b 00 00 00 0c 00 00 00 │ ················ │

字符串数组:char names[3][16] = {"AAA","BBBB","CCCCCCCCCCCCCCC"}; 。

1
2
3
41 41 41 00   00 00 00 00   00 00 00 00   00 00 00 00   │ AAA············· │
42 42 42 42 00 00 00 00 00 00 00 00 00 00 00 00 │ BBBB············ │
43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 00 │ CCCCCCCCCCCCCCC· │
多维动态数组

二维字符串数组创建方法一:
代码如下,4个字符串指针,决定了字符串的个数,指针所指向的地址由自己定义。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void *vp = malloc(16);
memset(vp, 0, 16);
memcpy(vp,"AAA",4);
memcpy(vp + 4, "BBB", 4);
memcpy(vp + 8, "CCC", 4);
memcpy(vp + 12, "DDD", 4);

char *str_arr_ptr[4];
str_arr_ptr[0] = vp;
str_arr_ptr[1] = vp + 4;
str_arr_ptr[2] = vp + 8;
str_arr_ptr[3] = vp + 12;
for (int i = 0; i < 4;i ++){
printf("str_arr_ptr_%d => %s\n",i,str_arr_ptr[i]);
}

内存:

1
41 41 41 00   42 42 42 00   43 43 43 00   44 44 44 00   │ AAA·BBB·CCC·DDD· │

输出:

1
2
3
4
str_arr_ptr_0 => AAA
str_arr_ptr_1 => BBB
str_arr_ptr_2 => CCC
str_arr_ptr_3 => DDD

二维字符串数组创建方法二:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void *vp = malloc(16);
memset(vp, 0, 16);
memcpy(vp,"AAA",4);
memcpy(vp + 4, "BBB", 4);
memcpy(vp + 8, "CCC", 4);
memcpy(vp + 12, "DDD", 4);

char **str_arr_ptr2 = NULL;
// 申请了4个指针
str_arr_ptr2 = calloc(4,sizeof(char *));

str_arr_ptr2[0] = vp;

str_arr_ptr2[1] = vp + 4;

str_arr_ptr2[2] = vp + 8;

str_arr_ptr2[3] = vp + 12;
for (int i = 0; i < 4;i ++){
printf("str_arr_ptr_%d => %s\n",i,str_arr_ptr2[i]);
}

说明
与第一种不同的是,每个指向字符串数组的指针都要自己去申请。但是,好处是动态的,大小可以自己决定。C指针编程实际上是对内存操作的编程。

Share 

 Previous post: Linux命令总结 Next post: linux自动更换壁纸 

© 2025 long

Theme Typography by Makito

Proudly published with Hexo