结构体—简单通讯录实现

结构体——简单通讯录实现

1、结构体知识回顾

1.1、结构体的声明

struct tag
{
   
    menmber-list;
    
}variable-list;

描述一个学生:

struct Stu
{
   
    char name[20];
    int age;
    char sex[5];
    char id[20];
};  // 分号不要忘记

1.2、结构体变量的创建和初始化

#include<stdio.h>
struct Stu
{
   
    char name[20]; // 姓名
    int age;       // 年龄
    char sex[15];  // 性别
    char id[20];   // 学号
};

int main()
{
   
    // 按结构体成员顺序初始化
    struct Stu s ={
   "李四", 20, "男", "1088200066"};
    printf("姓名: %s\n", s.name);
    printf("年龄: %s\n", s.age);
    printf("性别: %s\n", s.sex);
    printf("学号: %s\n", s.id);
    
    // 按指定的顺序初始化
    struct Stu s ={
   .age = 18, .name = "李四", .sex = "男", .id = "1088200066"};
    printf("姓名: %s\n", s.name);
    printf("年龄: %s\n", s.age);
    printf("性别: %s\n", s.sex);
    printf("学号: %s\n", s.id);
    return 0;
}

1.3、结构特殊声明

声明结构的时候可以不完全声明。

比如:结构体在声明的时候省略结构体标签

# include<stdio.h>
int main()
{
   
    // 定义一个匿名结构体
    struct
    {
   
        int x;
        int y;
    }point1, point2; // point1和point2是该结构体的两个实例
    
    // point1和point2赋值
    point1.x =  10;
    point1.y = 20;
    
    point2.x = 10;
    point2.y = 20;
    
    // 输出
    printf("point1:(%d %d)\n", point1.x, point2.y);
    printf("point2:(%d %d)\n", point1.x, point2.y);
    
    return 0;
}

定义匿名结构体:

  • struct 关键字后没有结构体命名(tag),而是直接定义了结构体成员(x 和 y).
  • 这种结构体只能在定义他的作用域内实现。(匿名结构体的类型没有全局或外部可见性,只有在定义它的地方才能操作该结构体的实例)

优点:

  • 简洁性: 在某些情况下,使用匿名结构体可以使代码更加简洁,尤其是在只需要使用一次的情况下
  • 局部性: 匿名结构体的作用域限制在定义他的地方,避免了命名冲突。

1.4、结构的自引用

​ 在结构体中不能包含一个类型为该结构体本身的成员,因为当结构体中再包含一个同类型的结构体变量,会使得结构体变量的大小变得无穷大,这是不合理的。但是可以包含该结构体成员的地址。

struct Node
{
   
    int data;
    struct Node* next;
};

在结构体⾃引⽤使⽤的过程中,夹杂了 typedef 对匿名结构体类型重命名,也容易引⼊问题.

问题代码:

typedef struct
{
   
    int data;
    Node* next;
}Node;

分析原因: 原理上上述代码执行完成后才完成对匿名结构体类型的重命名,但是在重命名过程中便引入了Node, 这便引起了先有鸡还是先有蛋的问题,显然是不对的。

解决方案:定义结构体不要使用匿名结构体

typedef struct Node
{
   
    int data;
    struct Node* next;
};

2、 结构体内存对齐

2.1 对齐规则

  1. 结构体的第一个成员对齐到和结构体变量起始位置偏移量为0的地址处。
  2. 其他成员变量要对齐到对齐数 的整数倍的地址处。
  3. 对齐数 = 编译器默认的对齐数和成员变量大小的较小值。
  4. VS中默认的对齐数是8。
  5. Linux中gcc没有默认的对齐数,对齐数是成员变量的自身大小。
  6. 结构体总大小为最大对齐数 (结构体总每个成员变量都有一个对齐数,所有对齐数中最大的)的整数倍。
  7. 如果嵌套了结构体的话,嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数的(含嵌套结构体成员的对齐数)的整数倍。

2.2、修改默认对齐数

#pragma 这个预处理指令,可以改变编译器的默认对齐数。

# include<stdio.h>
#pragma pack(1) // 设置默认对齐数为1
struct S
{
   
    char c1;
    int i;
    char c2;
};
#pragma pack() // 回复默认对齐数

int main()
{
   
	printf("%d\n", sizeof(struct S));
    return 0;
}

3、结构体传参

结构体传参最好传地址

#include<stdio,h>
struct S
{
   
    int data[100];
    int num;
};  // 不要忘记;
//  结构体传参
void print1(struct S s)
{
   
    printf("%d\n", s.num);
}
// 结构体传传参传地址
void print2(struct S* ps)
{
   
    printf("%d\n", ps->num);
}
int main()
{
   
    print1(S);
    print2(&S);
    return 0;
}

4、简单通讯录的实现

要求:

实现一个通讯录
人的信息:
名字+年龄+性别+电话+地址
存放100个人的信息、增加联系人、删除指定的练习人、查找练习人、修改联系人、排序、显示连续人

为了后期维护和 查看的方便我们将该项目写成多文件的形式。

test1.c main函数主程序

contact.c 各种函数的实现

contact.h 头文件和函数声明


test1.c

#include<stdio.h>

void menu()
{
   
	printf("******************************************\n");
	printf("******* 1.add              2.del    ******\n");
	printf("******* 3.search           4.modify ******\n");
	printf("******* 5.show             6.sort   ******\n");
	printf("******* 0.exit                      ******\n");
	printf("******************************************\n");
	printf("******************************************\n");

}

int main()
{
   
    int input = 0;
    do
    {
   
        menu();   // 打印菜单
        printf("请选择:>");
        scanf("%d", &input);
        switch(input)
        {
   
            case 1:
                break;
            case 2:
                break:
            case 3:
                break:
            case 4:
                break;
            case 5:
                break:
            case 6:
                break;
            case 0:
                printf("退出通讯录\n");
                break;
            default:
                
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值