14.C语言-结构体

1.组织数据

一个用户信息包括

  • 姓名
  • 邮箱
  • 手机号
  • 年龄

这里面包括了多个信息,每个信息类型可能不同,这里数组搞不定了。

使用结构体来封装一些属性,设计出新的类型,在C语言中称为结构体类型。

结构体类型定义的一般格式如下:

struct是定义结构体类型的关键字;结构体类型名必须是合法的C标识符,与其前面的struct一起共同构成结构体类型名;花括号内的内容是结构体类型所包括的结构体成员,也称为结构体成员。

struct User
{
  char name[50];
  char mobile[12];
  int age;
  char email[255];
};
//无名称结构体 
struct
{
  char name[50];
  char mobile[12];
  int age;
  char email[255];
};

内存分配,每个元素是独立的,有自己占用的空间

sprintf

函数用于将格式化的数据写入字符串,它将输出存储在sprintf中指定的char缓冲区中,而不是在控制台上进行打印

str -- 这是指向一个字符数组的指针,该数组存储了 C 字符串。 format -- 这是字符串,包含了要被写入到字符串 str 的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。 附加参数 -- 根据不同的 format 字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了 format 参数中指定的每个 % 标签。参数的个数应与 % 标签的个数相同。

返回值

如果成功,则返回写入的字符总数,不包括字符串追加在字符串末尾的空字符。如果失败,则返回一个负数

#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>

struct User
{
  char name[50];
  char mobile[12];
  int age;
  char email[255];
};

void main() {
  struct User user;//创建了一个结构体变量
  user.age = 10;
  printf("结构体编号:%d\n", user.age);
  sprintf(user.name, "张三");//将张三写入user.name
  strcpy(user.mobile, "17600999999");//用copy方式
  printf("%s\n", user.name);
  printf("%s\n", user.mobile);
  system("pause");
}

使用define ,这里只是做了一个简单的替换

#define SUser struct User 

#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>

SUser
{
  char name[50];
  char mobile[12];
  int age;
  char email[255];
};

void main() {
  SUser user;//创建了一个结构体变量
  user.age = 10;
  printf("结构体编号:%d\n", user.age);
  sprintf(user.name, "张三");//将张三写入user.name
  strcpy(user.mobile, "17600999999");//用copy方式
  printf("%s\n", user.name);
  printf("%s\n", user.mobile);
  system("pause");
}
#include<stdio.h>
#include<stdlib.h>

struct Person {
  int age;//结构体定义不能赋值
  char name[100];
};

void main() {
  struct Person p1 = { 99,"张三" };
  struct Person p2 = p1; 
  printf("%d,%s\n", p2.age, p2.name);
  //这里用字符串copy
  strcpy(p1.name, "李四");
  printf("%d,%s\n", p1.age, p1.name);
  printf("%d,%s\n", p2.age, p2.name);
  getchar();
}

结构体包含

struct Person {
  int age;//结构体定义不能赋值
  char name[100];
  //定义部门信息
  struct dept{
    char dept_name[20];
    int num;
  };
};

void main() {
  struct  Person p1;
  p1.age = 99;
  p1.num = 10;
  strcpy(p1.dept_name, "IT");
  strcpy(p1.name, "张三");
  printf("%d,%s,%d,%s", p1.age, p1.name,p1.num,p1.dept_name);
}

实例化一个结构体中的子结构体

#include<stdio.h>
#include<stdlib.h>


struct Person {
  int age;//结构体定义不能赋值
  char name[100];
  struct dept {
    char dept_name[20];
    int num;
  }d1;//这里是一个实例了
};

void main() {
  struct  Person p1;
  p1.age = 99;
  p1.d1.num = 10;
  strcpy(p1.d1.dept_name, "IT");
  strcpy(p1.name, "张三");
  printf("%d,%s,%d,%s", p1.age, p1.name,p1.d1.num,p1.d1.dept_name);
}

子结构体实例

struct Person {
  int age;//结构体定义不能赋值
  char name[100];
  struct dept {
    char dept_name[20];
    int num;
  }d1;//这里是一个实例了
  struct dept d2;
};

void main() {
  struct  Person p1;
  p1.age = 99;
  p1.d1.num = 10;
  strcpy(p1.d1.dept_name, "IT");
  strcpy(p1.name, "张三");
  p1.d2.num = 1000;
  printf("%d,%s,%d,%s,%d", p1.age, p1.name,p1.d1.num,p1.d1.dept_name,p1.d2.num);
}

匿名结构体

匿名结构体不会出现重合 重命名的情况

有名结构体 名称不能相同 也就是不能重名

#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
#include<stdlib.h>

//这个是匿名结构体
struct
{
  char name[50];
  int age;
  int dept[50];
};

struct
{
  char name[50];
  int age;
  int dept[50];
} u1, u2, u3; //这里实例化


void main() {
  u1.age = 10;
  u2.age = 20;
  u3.age = 40;
  sprintf(u1.name, "李四");
  printf("%d,%d,%d,%s", u1.age, u2.age, u3.age,u1.name);
}

2.结构体数组

声明的几种方法

struct Person
{
  char name[30];
  int age;
};

void main() {
  struct Person b1[2];
  sprintf(b1[0].name, "张三");
  printf("%s", b1[0].name);
}
struct Person
{
  char name[30];
  int age;
}p[20];

void main() {
  sprintf(p[0].name, "张三");
  printf("%s", p[0].name);
}
struct Person
{
  char name[30];
  int age;
}p[20];

void main() {
  sprintf(p[0].name, "张三");
  printf("%s", p[0].name);
}

查看内存

#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
#include<stdlib.h>


struct data
{
  int qty;
  float f1;
  char name[4];
}db[3] = {
  {1,1.0,"A"},
  {2,2.0,"B"},
  {3,3.0,"C"}
};

void main() {
  printf("%p\n", &db);
  printf("%p\n", &db[0]);
  printf("%p\n", &db[1]);
  printf("%p\n", &db[2]);
  getchar();
}

结构体数组在内存中也是一个个排列的。

3.结构体指针

指向结构体变量的指针

struct person *p

#include<stdio.h>
#include<stdlib.h>

struct Person {
  int num;
  int age;
  char name[100];
};

void main() {
  struct Person person;
  person.num = 1;
  person.age = 99;
  strcpy(person.name, "张三");
  printf("%s\n", person.name);

  //用结构体指针保存一个地址
  struct Person* p;
  p = &person;
  printf("%d,%s\n", (*p).num,(*p).name);
  printf("%d,%s", p->num, p->name);
}

可以用→访问一个指针结构体

指向结构体数组的指针

struct data
{
  int qty;
  float f1;
  char name[4];
}db[3] = {
  {1,1.0,"A"},
  {2,2.0,"B"},
  {3,3.0,"C"}
};

void main() {
  struct data* d;
  d = db;
  for (int i = 0; i < 3; i++)
  {
    printf("%d,%f,%s\n", d->qty, d->f1, d->name);
    d++;
  }
}
void main() {
  for (struct data *p =db ; p < db+3; p++)
  {
    printf("%d,%f,%s\n", p->qty, p->f1, p->name);
  }
}

用指向结构体的指针作函数参数

  • 用结构体变量的成员作参数
  • 用指向结构体变量或数组的指针作参数
  • 用结构体变量作参数

用结构体作参数,内存消耗多

#include<stdio.h>
#include<stdlib.h>

struct data
{
  int qty;
  float f1;
  char name[4];
};

void changedata(struct data *d) {
  d->qty = 100;
}

void main() {
  struct data d;
  d.qty = 1;
  printf("%d\n", d.qty);
  changedata(&d);
  printf("%d", d.qty);
}

4.union共用体

union 共用体名{

    成员列表  

};

共用体有时也被称为联合或者联合体,这也是 Union 这个单词的本意。

结构体和共用体的区别在于:结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。

结构体占用的内存大于等于所有成员占用的内存的总和,共用体占用的内存等于最长的成员占用的内存。共用体使用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会把原来成员的值覆盖掉。

union的大小取决于最大的一个成员变量大小

union Data
{
  int i;
  float f;
  char  str[20];
};

int main()
{
  union Data data;

  printf("内存大小 : %d\n", sizeof(data));

  return 0;
}
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>

union data {
  int n;
  char name[20];
  double d;
};

void main() {
  union data d1;
  d1.d = 10;
  d1.n = 99;
  sprintf(d1.name, "张三");
  printf("%d\n", d1.n);
  printf("%f\n", d1.d);
  printf("%s\n", d1.name);
}

看一下这段,内存地址

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>

union data {
  long l;
  int i;
};

void main() {
  union data d;
  d.l = 5;
  printf("%d,%p\n", d.l, &d.l);
  d.i = 6;
  printf("%d,%p\n", d.i,&d.i);
  printf("%d,%p\n", d.l, &d.l);
}

其实总结union,就是一个固定首地址,按最大类型给你一段内存空间。

几种申明方式,这里与struct基本一样的。

union data
{
    int i;
    char ch;
    float f;
}a, b;
union
{
    int i;
    char ch;
} a,b;
//联合体模板union perdata重新命名为perdata_U
typedef union perdata
{
    int i;
    char ch;
} perdata_U;
// 使用新名字perdata_U创建两个变量a, b
void main() {
    perdata_U a, b;
}

再次看一下长度是怎么计算出来的

union Data
{
  int i;
  char str[10];
};

int main()
{
  union Data data;

  printf("内存大小 : %d\n", sizeof(data));

  return 0;
}

这里会是12,为什么是12,第一步,成员变量最长是的是int,它是4个字节,char只是1,这里千万不是认为是按变量长度计算的,4的整数倍*3=12,可以大于str[10],因些长度就是12了。

共用体变量引用

union Data
{
  int i;
  char str[10];
};

int main()
{
  union Data data;
  union Data* d1 = &data;
  data.i = 1;
  printf("%d\n", d1->i);
  sprintf(data.str, "hi");
  printf("%s\n",  d1->str);
  return 0;
}

共用体在一般的编程中应用较少,在单片机中应用较多。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>

struct User {
  char name[40];
  union Age {
    int age;
    char status[20];
  } AS;
};

void main() {
  struct User user1;
  sprintf(user1.name, "张三");
  int age = 0;
  scanf("%d", &age);
  if (age < 0 || age>150) {
    sprintf(user1.AS.status, "出错了");
    printf("%s,%s", user1.name, user1.AS.status);
  }
  else {
    user1.AS.age = age;
    printf("%s,%d", user1.name, user1.AS.age);
  }  
}

5.枚举类型

枚举是 C 语言中的一种基本数据类型,用于定义一组具有离散值的常量。,它可以让数据更简洁,更易读。

枚举类型通常用于为程序中的一组相关的常量取名字,以便于程序的可读性和维护性。

定义一个枚举类型,需要使用 enum 关键字,后面跟着枚举类型的名称,以及用大括号 {} 括起来的一组枚举常量。每个枚举常量可以用一个标识符来表示,也可以为它们指定一个整数值,如果没有指定,那么默认从 0 开始递增。

enum 枚举名 {枚举元素1,枚举元素2,……};

enum DAY
{
    MON = 1, TUE, WED, THU, FRI, SAT, SUN
};
enum  DAY day;

enum DAY
{
    MON = 1, TUE, WED, THU, FRI, SAT, SUN
} day;
enum
{
    MON = 1, TUE, WED, THU, FRI, SAT, SUN
} day;
enum DAY
{
    MON = 1, TUE, WED, THU, FRI, SAT, SUN
};

void main() {
   enum  DAY day;
   day = FRI;
   printf("%d", day);//5
}
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>


enum DAY
{
    MON = 1, TUE, WED, THU, FRI, SAT, SUN
};

void main() {
   enum  DAY day;
   printf("请输入今天星期几:\n");
   scanf("%d", &day);
   switch (day)
   {
   case MON:
       printf("怎么就周一了!!!");
       break;
   case TUE:
       printf("痛苦的周二!!!");
       break;
   case WED:
       printf("没有盼头的周二!!!");
       break;
   case THU:
       printf("总算看到希望了!!!");
       break;
   case FRI:
       printf("快乐的周五!!!");
       break;
   case SAT:
       printf("浪!!!");
       break;
   case SUN:
       printf("浪!!!");
       break;
   default:
       break;
   }
}

在没有用枚举前,想想这个是不是了可以。

#define Mon 1
#define Tues 2
#define Wed 3
#define Thurs 4
#define Fri 5
#define Sat 6
#define Sun 7

用枚举类型声明枚举变量时,只能取集合中的某项作为其值,这在一定程度上保证了取值的安全性。

6.Typedef

C 语言提供了 typedef 关键字,您可以使用它来为类型取一个新的名字。

  1. 按定义变量方法先写出定义体 如 int i;
  2. 将变量名换成新类型名 如 int INTEGER;
  3. 最前面加typedef 如 typedef int INTEGER;
  4. 用新类型名定义变量 如 INTEGER i,j;

注意:

  • typedef 没有创造新数据类型;
  • typedef 是定义类型,不能定义变量;
  • typedef 与 define 不同(define:预编译时处理、简单字符置换;typedef:编译时处理、为已有类型命名。)
typedef int 整数;

void main() {
  整数 x = 100;
}
#define 整数 int

void main() {
  整数 x = 100;
}

我们定义一个BYTE类型

typedef unsigned char BYTE;

void main() {
  BYTE b1, b2;
  b1 = 'A';
  printf("%c", b1);
}

定义一个书的自定义类型

typedef struct Books {
  char  title[50];
  char  author[50];
  char  subject[100];
  int   book_id;
} Book;

int main() {
  Book book;
  strcpy(book.title, "C 教程");
  strcpy(book.author, "MICROSOFT");
  strcpy(book.subject, "开发");
  book.book_id = 1;
}

7.练习

指针初使化结构体

struct School {
  char name[50];
  int id;
};

void main() {
  struct School* p;
  p = (union school*)malloc(sizeof(struct School));
  p->id = 10;
  strcpy(p->name, "北大");
  printf("%d\n", p->id);
  printf("%s", p->name);
}

指针初使化共用体

union School {
  char name[50];
  int id;
};

void main() {
  union School* p;
  p = (union school*)malloc(sizeof(union School));
  p->id = 10;
  printf("%d\n", p->id);
  strcpy(p->name, "北大");
  printf("%s", p->name);
}

复杂结构体

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

struct School {
  char name[50];
  int id;
  struct Student {
    char name[50];
    int age;
  } ST[10];
};

void main() {
  struct School school;
  sprintf(school.name, "北京大学");
  school.id = 1;
  for (int i = 0; i < 10; i++)
  {
    school.ST[i].age = 10*(i+1);
    char no[2];
    _itoa(i, no, 10);//将i以10进制的形式写入no中
    char name[20] = "张飞";
    strcat(name, no);//链接两个字符串
    sprintf(school.ST[i].name, name);
  }
  for (int i = 0; i < 10; i++)
  {
    printf("%s,%d\n", school.ST[i].name
      , school.ST[i].age);
  }
}
原文链接:,转发请注明来源!