数据结构(基于C)Makefile与顺序表 6.14

发布于:2025-06-19 ⋅ 阅读:(20) ⋅ 点赞:(0)

前言

        在之前的C基础学习过程中,我们对多文件编译有了一个基本的认识。

        为了优化编译过程,这里我们引入makefile,通过makefile实现多文件编译,进而实现对顺序表的不同操作。

概述

        1.基础

        2.练习

1.基础

1.1:对C语言的复习

段错误:

1.数组越界,

2.静态区只读段修改,

3.数据结构,野指针与悬空指针,

4.空指针的间接访问

指针函数:

指针函数不能返回栈区的地址(栈区会自动释放内存)

指针函数可返回的类型:

1.主调函数传递过去的地址(参数地址)

2.堆区申请的空间(堆区)

3.全局变量地址(静态区)

4.Static静态局部变量地址(Static变量是令局变量,在.bss/.data段)

悬空指针:

1.对这块地址无法访问的指针

2.堆区申请地址后free将变成悬空指针

1.2: Makefile

  • 第一版

    • all : 01_test

    • 01_test : main.o fun.o

      • gcc main.o fun.o -o ol_test

    • main.o : main.c

      • gcc main.c -c -o main.o

    • fun.o : fun.c

      • gcc fun.c -c -o fun.o

all:01_test
01_test:main.o fun.o
	gcc main.o fun.o -o 01_test
main.o:main.c
	gcc -c main.c -o main.o
fun.o:fun.c
	gcc -c fun.c -o fun.o
  • 第二版

    • EXE = 01_test

    • Objs += main.o

    • Objs += fun.o

    • CC = gcc

    • CFlags = -c -o

    • all : $(EXE)

    • $(EXE) : $(Objs)

      • $(CC) $(Objs) -o $(EXE)

    • main.o : main.c

      • $(CC) main.c -c -o main.o

    • fun.o : fun.c

      • $(CC) fun.c -c -o fun.o

第三版

  1. 变量定义和初始化

    • Objst += main.o

    • Objst += fun.o

    • CC = gc

    • CFlags = -c -o

  2. 命令和参数

    • all: $(CEXE)

    • $(EXE): $(Objst)

    • $(ICC) $^ -o $@

    • %.o: %.c

    • $(CC) $^ $ (CFlags) $@

  3. PHONY指令

    • .PHONY: clean

    • clean:

    • rm $(EXE) $(Objst)

第四版

EXE=01_text
Objs+=main.o
Objs+=fun.o
CC=gcc
CFlags=-c -o

all:$(EXE)
$(EXE):$(Objs)
	$(CC) $^ -o $@
%.o:%.c
	$(CC) $^ $(CFlags) $@

#伪目标
.PHONY:clean
clean:
	rm $(EXE) $(Objs)

符号说明部分

  1. 符号 $!

    • 提取最后一次赋值结果

  2. 符号 :

    • +:递归赋值:最后一次赋值

    • +=:递归后再追加

    • :=:立即赋值:不计算,直接赋值

    • ?=:条件赋值:只要变量存在,就会赋值

  3. 符号 $@

    • 所有目标

  4. 符号 $^

    • 所有依赖

  5. 符号 %

    • 通配符,匹配指定格式 %.o: %.c

  6. 符号 $(wildcard *.c)

    • 获取当前路径下所有 .c 文件

  7. 符号 $(patsubst %.c, %.o, fun.c main.c)

    • 将 .c 换为 .o

  8. make 命令相关

    • make -f <filename>:打开并执行文件

    • make clean:执行 clean 指令

1.3:手写笔记

2.练习

题目:实现顺序表的头插、尾插、头删、尾删(释放顺序表):

1.首先touch一个Makefile文件

EXE=01_seq_list
Objs+=01_seq_list_main.o
Objs+=01_seq_list_fun.o
CC=gcc
CFlags=-c -o

all:$(EXE)
$(EXE):$(Objs)
	$(CC) $^ -o $@
%.o:%.c
	$(CC) $^ $(CFlags) $@

#伪目标
.PHONY:clean
clean:
	rm $(EXE) $(Objs)

2.之后分别在三个文件中写入代码:

2.1:01_seq_list.h

#ifndef _HEAD_H_
#define _HEAD_H_

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 6
typedef struct seq_list
{
    int arr[MAX];      //存储数据的数组
    int len;           //记录实际长度
}seq_list,*seq_p;

//声明函数
void puts_arr(seq_p S); //0.1
seq_p create_seqlist(); //1
int empty_seq(seq_p S); //2
int full_seq(seq_p S);  //3
void insert_head(seq_p S,int data);//4
void insert_end(seq_p S,int data);//5
void delete_head(seq_p S);//6
void delete_end(seq_p S);//7

#endif

2.2:01_seq_list_main.c

#include "01_seq_list_head.h"
//0.1 打印数组
void puts_arr(seq_p S)
{
    for(int i=0;i<=S->len-1;++i)
    {
        printf("%d ",S->arr[i]);
    }
    printf("\n");
}
//1、申请堆区内存
seq_p create_seqlist()
{
    //从堆区申请一个结构体的空间
    seq_p S = (seq_p)malloc(sizeof(seq_list));
    if(S==NULL)
    {
        return NULL;
    }
    //如果申请空间成功
    //将堆区申请的一个结构体的空间都清0
    memset(S,0,sizeof(seq_list));
    return S;
}
//2、判空
int empty_seq(seq_p S)
{
    if(S==NULL)
    {
        printf("入参为空\n");
        return -2;
    }
    //判断如果len为0说明顺序表为空
    return S->len==0?1:0;
}
//3、判满
int full_seq(seq_p S)
{
    if(S==NULL)
    {
        printf("入参为空\n");
        return -2;
    }
    //如果长度和数组的最大长度相等顺序表已满
    return S->len==MAX?1:0;
}
//4、头插
void insert_head(seq_p S,int data)
{
    if(full_seq(S))
    {
        printf("顺序表已满,不可头插\n");
        return;
    }
    else
    {
        for(int i=S->len-1;i>=0;--i)
        {
            S->arr[i+1]=S->arr[i];
        }
        S->arr[0]=data;
        S->len++;       //更新长度
    }
}
//5、尾插
void insert_end(seq_p S,int data)
{
    if(full_seq(S))
    {
        printf("顺序表已满,不可尾插\n");
        return;
    }
    else
    {
        S->arr[S->len]=data;
        S->len++;       //更新长度
    }
}
//6、头删
void delete_head(seq_p S)
{
    if(empty_seq(S))
    {
        printf("顺序表为空,不可头删\n");
        return;
    }
    else
    {
        for(int i=0;i<=S->len-1-1;++i)
        {
            S->arr[i]=S->arr[i+1];
        }
        S->len--;
    }
}
//7、尾删
void delete_end(seq_p S)
{
    if(empty_seq(S))
    {
        printf("顺序表为空,不可尾删\n");
        return;
    }
    else
    {
        S->len--;       //更新长度
    }
}

2.3:01_seq_list_fun.c

#include "01_seq_list_head.h"
int main(int argc, const char *argv[])
{
    //申请空间并初始化
    seq_p S=create_seqlist();
    memset(S->arr,0,S->len);

    //给顺序表赋值并查看
    int arr_dest[]={1,1,1,1,1};
    memcpy(S->arr,arr_dest,sizeof(S->arr));
    S->len=5;//S->len=sizeof(arr_dest); :错误写法
    puts_arr(S);

    //实现头插并查看
    insert_head(S,9);
    printf("头插9:");
    puts_arr(S);

    //通过判满检查是否头插成功
    printf("判满?:%d\n",full_seq(S));

    //尾删
    delete_end(S);
    printf("尾删 :");
    puts_arr(S);

    //尾插
    insert_end(S,9);
    printf("尾插9:");
    puts_arr(S);

    //头删
    delete_head(S);
    printf("头删 :");
    puts_arr(S);

    //释放内存,结束main函数
    free(S);
    S=NULL;
    return 0;
}   

3.运行:

ubuntu@ubuntu:~/data_structre$ make -f makefile4
gcc 01_seq_list_fun.c -c -o 01_seq_list_fun.o
gcc 01_seq_list_main.o 01_seq_list_fun.o -o 01_seq_list
ubuntu@ubuntu:~/data_structre$ ./01_seq_list 
1 1 1 1 1 
头插9:9 1 1 1 1 1 
判满?:1
尾删 :9 1 1 1 1 
尾插9:9 1 1 1 1 9 
头删 :1 1 1 1 9 
ubuntu@ubuntu:~/data_structre$ 

结语

        顺序数组本质上是结构体,需要遵循结构体相关的基本的C语言语言规则。


网站公告

今日签到

点亮在社区的每一天
去签到