一.
深入讨论一个问题:计算结构体的大小
这也是一个特别热门的考点: 结构体内存对齐
//练习
struct S1
{
char c1;
char c2;
int i;
};
printf("%d\n", sizeof(struct S1));
//练习
struct S2
{
double d;
char c;
int i;
};
printf("%d\n", sizeof(struct S2));
//练习-结构体嵌套问题
struct S3
{
char c1;
struct S2 s2;
double d;
};
printf("%d\n", sizeof(struct S3));
-
考点 如何计算? 首先得掌握结构体的对齐规则:
1.第一个成员在与结构体变量偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。 对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。*VS中默认的值为8*
3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
为什么存在内存对齐? 大部分的参考资料都是如是说的:
- 平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能 在某些地址处取某些特定类型的数据,否则抛出硬件异常。
- 性能原因: 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的 内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
总体来说: 结构体的内存对齐是拿空间来换取时间的做法。
那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到?
让占用空间小的成员尽量集中在一起。
修改默认对齐数
之前我们见过了 #pragma 这个预处理指令,这里我们再次使用,可以改变我们的默认对齐数。
#pragma pack(8)//设置默认对齐数为8
struct S1
{
char c1;
int i;
char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默
二.
实现一个通讯录
通讯录可以用来存储1000个人的信息,每个人的信息包括:姓名、性别、年龄、电话、住址
提供方法:
添加联系人信息
删除指定联系人信息
查找指定联系人信息
修改指定联系人信息
显示所有联系人信息
清空所有联系人
以名字排序所有联系人
//call.h
#ifndef __CALL_H__
#define __CALL_H__
#define _CRT_SECURE_NO_WARNINGS 1
#pragma warning(disable : 4996)
#include<stdio.h>
#include<Windows.h>
#include<string.h>
typedef struct callman
{
char name[20];
char sex[10];
int age;
int tel[12];
char addr[50];
}callman;
typedef struct status
{
callman num[1000];
int count;
}status;
void myinit(status* p);//chushihua
void myadd(status* p);//tianjia
void mydele(status* p);//shanchu
void myfind(status* p);//chauzhao
void myrevise(status* p);//xiugai
void mydisplay(status* p);//xianshi
void myempty(status* p);//qingkong
void mysort(status* p);//paixu
#endif // !__CALL_H__
//call.c
#include "call.h"
int Find(status *p,char *pname)
{
int i = 0;
for (i = 0; i < (p->count); i++)
{
if (strcmp(p->num[i].name, pname) == 0)
return i;
}
return -1;
}
void menu1()
{
printf("*******************\n");
printf("1.name 2.sex\n");
printf("3.age 4.tele\n");
printf("5.addr 0.return\n");
printf("*******************\n");
}
void myinit(status* p)//chushihua
{
int count = sizeof(p->num);
p->count = 0;
memset(p->num, 0, count);
}
void myadd(status* p)//tianjia
{
printf("xinming:\n");
scanf("%s", p->num[p->count].name);
printf("xinbie:\n");
scanf("%s", p->num[p->count].sex);
printf("nianling:\n");
scanf("%d", &(p->num[p->count].age));
printf("telenum:\n");
scanf("%s", p->num[p->count].tel);
printf("address:\n");
scanf("%s", p->num[p->count].addr);
if (p->count > 1000)
{
printf("shangxian\n");
}
else
{
printf("success\n");
p->count++;
}
}
void mydele(status* p)//shanchu
{
char name[20] = { 0 };
int result = 0;
int n = 0;
int i = 0;
printf("dele name\n");
scanf("%s", name);
result = Find(p, name);
if (result != -1)
{
printf("shifousanchu?\n");
printf("yes.1 no.0\n");
scanf("%d", &n);
if (1 == n)
{
for (i = 0; i < (p -> count) - 1; i++)
{
p->num[i] = p->num[i + 1];
}
p->count--;
printf("success\n");
}
else
{
printf("fail\n");
}
}
else
{
printf("bucinzai\n");
}
}
void myfind(status* p)//chauzhao
{
char name[20] = { 0 };
int result = 0;
printf("find name:\n");
scanf("%s", name);
result = Find(p, name);
if (result != -1)
{
printf("name:%s\n", p->num[result].name);
printf("sex:%s\n", p->num[result].sex);
printf("age:%d\n", p->num[result].age);
printf("tel:%s\n", p->num[result].tel);
printf("addr:%s\n", p->num[result].addr);
}
else
{
printf("bucinzai\n");
}
}
void myrevise(status* p)//xiugai
{
char name[20] = { 0 };
int result = 0;
printf("input xiugainame\n");
scanf("%s", name);
result = Find(p, name);
if (result != -1)
{
printf("name:%s\n", p->num[result].name);
printf("sex:%s\n", p->num[result].sex);
printf("age:%d\n", p->num[result].age);
printf("tel:%s\n", p->num[result].tel);
printf("addr:%s\n", p->num[result].addr);
int i = 0;
do {
menu1();
printf("shuruxiugaixiang:\n");
scanf("%d", &i);
switch (i)
{
case 1:
printf("name:");
scanf("%s", p->num[result].name);
break;
case 2:
printf("sex:");
scanf("%s", p->num[result].sex);
break;
case 3:
printf("age:");
scanf("%d", p->num[result].age);
break;
case 4:
printf("telenum:");
scanf("%s", p->num[result].tel);
break;
case 5:
printf("address:");
scanf("%s", p->num[result].addr);
break;
case 0:
break;
default:
printf("error");
break;
}
} while (i);
}
else
{
printf("bucunzai!\n");
}
}
void mydisplay(status* p)//xianshi
{
int i = 0;
printf("shuchuxinxi\n");
printf("%10s%7s%6s%8s%10s\n", "name", "sex", "age", "tele", "addr");
for (i = 0; i < (p->count); i++)
{
printf("%11s", p->num[i].name);
printf("%5s", p->num[i].sex);
printf("%5d", p->num[i].age);
printf("%10s", p->num[i].tel);
printf("%12s", p->num[i].addr);
printf("\n");
}
}
void myempty(status* p)//qingkong
{
p->count = 0;
}
void mysort(status* p)//paixu
{
int i = 0;
int j = 0;
for (i = 0; i < p->count - 1; i++)
{
for (j = 0; j < p->count - 1 - i; j++)
{
if (strcmp(p->num[j].name, p->num[j + 1].name) > 0)
{
callman tmp;
tmp = p->num[j];
p->num[j] = p->num[j + 1];
p->num[j + 1] = tmp;
}
}
}
}
//test.c
#include "call.h"
status p;
void memu()
{
printf("***********************************\n");
printf("1.添加\n");
printf("2.删除\n");
printf("3.查找\n");
printf("4.修改\n");
printf("5.显示\n");
printf("6.清空\n");
printf("7.排序\n");
printf("0.退出\n");
printf("***********************************\n");
}
void test()
{
int i = 0;
do
{
memu();
printf("shuru:");
scanf("%d", &i);
switch (i)
{
case 1:myadd(&p);
break;
case 2:mydele(&p);
break;
case 3:myfind(&p);
break;
case 4:myrevise(&p);
break;
case 5:mydisplay(&p);
break;
case 6:myempty(&p);
break;
case 7:mysort(&p);
break;
case 0:exit(1);
break;
default:
printf("error\n");
break;
}
} while (i);
}
int main()
{
myinit(&p);
test();
return 0;
}