C语言结构体笔记

结构体

为什么需要结构体

为了表示一些复杂的事物,而普通的基本类型无法满足实际要求

为什么叫结构体

把一些基本类型数据组合在一起形成的一个新的复合数据类型

如何定义一个结构体

3种方式,最好使用第一种

#include <stdio.h>

struct Student //第一种方式  这只是定义了一个新的数据类型,并没有定义变量
{
    int age;
    float score;
    char name[100];
};

struct Student2 //第二种方式
{
    int age;
    float score;
    char name[100];
}st2;

struct //第三种方式
{
    int age;
    float score;
    char name[100];
}st3;

怎么去使用结构体变量

赋值和初始化

定义的同时可以整体赋初值

如果定义完之后,则只能单个的赋初值

#include <stdio.h>

struct Student 
{
    int age;
    float score;
    char sex;
};

int main()
{
    struct Student st = {80, 66.6, 'F'}; //初始化  定义的同时赋初值
    struct Student st2;
    st2.age = 10;
    st2.score = 88;
    st2.sex = 'F';

    printf("%d %f %c\n", st.age, st.score, st.sex);
    printf("%d %f %c\n", st2.age, st2.score, st2.sex);

    return 0;
}

如何取出结构体变量中的每一个成员

1.结构体变量名.成员名

2.指针变量名–>成员名 (第二种方式更常用)

——*在计算机内部会被转化(指针变量名).成员名的方式来执行

#include <stdio.h>

struct Student
{
    int age;
    float score;
    char sex;
};//分号不能省略

int main()
{
    struct Student st = {80, 66.6F, 'F'};
    struct Student *pst = &st;  //&st 不能够改成st

    pst->age =  88; //第二种方式

    st.score = 66.6f; //第一种方式
    //66.6在C中默认是double类型,如果希望一个实数是float类型,则必须在末尾加F或f,
    //因此66.6是double,66.6f是float

    printf("%d %.2f\n", st.age, pst->score);

    return 0;
}

/*
1.pst->age 在计算机内部会被转化(*pst).age 这是一种硬性规定
2.所以pst->age 等价于(*pst).age 也等价于 st.age
3.我们之所以知道pst->age 等价于 st.age, 是因为pst->age是被转换成了(*pst).age来执行
4.pst->age 的含义:pst所指向的那个结构体变量中age的成员
*/

结构体变量和结构体指针变量作为函数参数传递问题

推荐使用结构体指针变量作为函数参数来传递

#include <stdio.h>
#include <string.h>

struct Student
{
    int age;
    char sex;
    char name[100];
}; //分号不能省略

void InputStudent(struct Student * pstu); //函数形参涉及结构体类型,要在声明结构体后再声明函数
void OutputStudent(struct Student *pst);

int main()
{
    struct Student st;

    InputStudent(&st);//对结构体变量输入,必须发送st的地址
    OutputStudent(&st);//对结构体变量输出,可以发送st的地址也可以发送其内容
    //但为了减少内存的耗费也为了提高执行速度,推荐使用地址
    return 0;
}

void InputStudent(struct Student * pstu)//pstu只占4个字节
{
    (*pstu).age = 10;  //等价于st.age
    strcpy(pstu->name, "张三");
    pstu->sex = 'F';
}

/*
//本函数无法修改主函数st的值,error
void InputStudent(*struct Student stu)
{
    stu.age = 10;
    strcpy(stu.name, "张三"); //不能写成stu.name = "张三"
    stu.sex = 'F';
}
*/

void OutputStudent(struct Student *pst)
{
    printf("%d %c %s\n", pst->age, pst->sex, pst->name);
}

结构体变量的运算

结构体变量不能相加减乘除,但是结构体变量可以相互赋值

struct Student
{
    int age;
    float score;
    char sex;
};//分号不能省略

struct Student st1;
struct Student st2;
st1+st2; st1-st2; st1*st2; st1/st2; //都是错误的
st1 = st2; //正确
动态构造存放学生信息的结构体数组

动态构造一个数组,存放学生信息,然后按分数排序输出

#include <stdio.h>
#include <malloc.h>

struct Student
{
    int age;
    float score;
    char name[100];
};

void Output(int i,  struct Student * parr);
void sort(struct Student * parr , int len);
void Iutput(int len,  struct Student * parr);

int len;
struct Student * parr;
int i,j;
struct Student t;

int main()
{
    printf("请输入学生个数:\n");
    printf("len = ");
    scanf("%d", &len);
    parr = (struct Student *)malloc(len * sizeof(struct Student));//构造动态的一维数组

    Iutput(len, parr);
    //按学生的成绩升序排序
    sort(parr, len);
    printf("\n\n学生的信息是:\n");
    //输出
    Output(len, parr);

    return 0;
}


void Output(int len,  struct Student * parr)
{
    //输出
    for(i=0; i<len; ++i)
    {
        printf("第%d个学生信息:\n", i+1);
        printf("age = %d\n", parr[i].age);
        printf("name = %s\n", parr[i].name);
        printf("score = %.2f\n", parr[i].score);

        printf("\n");

    }
}

void Iutput(int len,  struct Student * parr)
{
    for(i=0; i<len; ++i)
    {
        printf("请输入%d个学生信息:", i+1);
        printf("age = ");
        scanf("%d", &parr[i].age);

        printf("name = ");
        scanf("%s",parr[i].name); //name是数组名,本身就已经是数值首元素的地址,所以parr[i].name不能够改为&parr[i].name

        printf("score = ");
        scanf("%f", &parr[i].score);

    }

}

void sort(struct Student * parr , int len )
{
    for(i=0; i<len-1; ++i)
    {
        for(j=0; j<len-1-i; ++j)
        {
            if(parr[j].score > parr[j+1].score) //比较成绩 互换整体
            {
                t = parr[j];
                parr[j] =parr[j+1];
                parr[j+1] = t;
            }
        }
    }
}

函数声明要在结构体之后

error: conflicting types for '***'

error: previous implicit declaration of '***' was here

      原因一:

      没有函数声明,且函数定义在主函数之后;

      原因二:

      头文件的被循环引用,在引用时考虑清楚包含顺序

      原因三:

      头文件函数声明和函数定义参数不同

      头文件中声明 void test(const char * buf);

      在定义时写作 void test(char * buf);

      

原因四:函数使用的参数类型是自定义类型(如结构体),而自定义类型的定义在函数的声明和函数定义之间,由于在函数声明时,结构体并没有被定义,不被系统识别为结构体,而后面定义函数时,结构体已经定义,系统将其识别为结构体,导致系统认为声明和定义使用的是不同的参数类型;所以才会出现上述问题;

      

算法定义

通俗定义

解题的方法和步骤

狭义定义

1.对存储数据的操作

2.对不同的存储结构,要完成某一个功能所执行的操作是不一样的

exp:要输出数组中所有的元素的操作 和 要输出链表中所有元素的操作肯定是不一样的

这说明算法是依附于存储结构的,不同的存储结构所执行的算法是不一样的

广义定义

1.广义的算法也叫泛型

2.无论数据是如何存储的,对该数据的操作都是一样的

int a[10] = {……};
int * ph = a;

for (i=0; i<10; ++i)
{
    printf("%d\n", *ph);
    ph++; //若是使用链表,假设有++函数视为ph = ph -> pNext;
    	  //若上述不成立无法实现++函数,则不能够套用在链表上
}

我们至少可以通过两种结构来存储数据

数组
缺点

1.需要一个连续的很大的内存

2.插入和删除元素的效率很低

优点

存取速度快

链表
优点

1.插入删除元素效率高

2.不需要一个连续的很大的内存

缺点

查找某个位置的元素效率低

专业术语
1.头结点:

头结点的数据类型和首节点的类型一模一样的

头结点是首节点前面的那个节点;

头结点并不存放有效数据;

设置头结点的目的是为了方便对链表的操作;

2.头指针:

存放头结点地址的指针变量

3.首节点:

存放第一个有效数据的节点

4.尾节点:

存放最后一个有效数据的节点

确定一个链表需要一个参数:头指针

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

struct Node
{
    int data;  //数据域
    struct Node * pNext;  //指针域  递归
};

//函数声明
struct Node * Create_List(void);
void Traverse_List(struct Node * pHead);
bool empty_list(struct Node * pHead);

int main()
{
    struct Node * pHead = NULL; //pHead用来存放链表头结点的地址

    pHead = Create_List(); //创建一个链表,并将信息传递给主函数
    Traverse_List(pHead);  //对链表进行输出

    return 0;
}


struct Node * Create_List(void)
{
    int len; //用来存储有效节点的个数
    int i;
    int val; //用来临时存储用户输入的结点的值

    //分配了一个不存放有效数据的头结点

    struct Node * pHead = (struct Node *)malloc(sizeof(struct Node));
    if (NULL == pHead)
    {
        printf("分配失败,程序终止!\n");
        exit(-1);  //终止程序
    }

    struct Node * pTail = pHead;
    pTail->pNext = NULL;

    printf("请您输入您需要生成的链表结点的个数:len =  ");
    scanf("%d", &len);

    for (i=0; i<len; ++i)
    {
        printf("请输入第%d个节点的值:", i+1);
        scanf("%d", &val);

        struct Node * pNew = (struct Node *)malloc(sizeof(struct Node));
        if (NULL == pNew)
        {
            printf("分配失败,程序终止!\n");
            exit(-1);
        }
        pNew->data = val;
        pTail->pNext = pNew;
        pNew->pNext = NULL;
        pTail = pNew;
    }
    return pHead;
};

bool empty_list(struct Node * pHead)
{
    if ( pHead->pNext == NULL ) //pHead->pNext == (*pHead).pNext
        return true;
    else
        return false;
}

void Traverse_List(struct Node * pHead)
{
    struct Node * p = pHead->pNext;

    /*if(empty_list(pHead))
    {
        printf("链表为空");
    }*/

    while (NULL != p)
    {
        printf("%d  ", p->data);
        p = p->pNext;
    }
    printf("\n");

    return;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值