前言
在之前的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.ogcc main.o fun.o -o 01_test
main.o:main.cgcc -c main.c -o main.o
fun.o:fun.cgcc -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
-
-
第三版
-
变量定义和初始化
-
Objst += main.o
-
Objst += fun.o
-
CC = gc
-
CFlags = -c -o
-
-
命令和参数
-
all: $(CEXE)
-
$(EXE): $(Objst)
-
$(ICC) $^ -o $@
-
%.o: %.c
-
$(CC) $^ $ (CFlags) $@
-
-
PHONY指令
-
.PHONY: clean
-
clean:
-
rm $(EXE) $(Objst)
-
第四版
EXE=01_text
Objs+=main.o
Objs+=fun.o
CC=gcc
CFlags=-c -oall:$(EXE)
$(EXE):$(Objs)$(CC) $^ -o $@
%.o:%.c$(CC) $^ $(CFlags) $@#伪目标
.PHONY:clean
clean:rm $(EXE) $(Objs)
符号说明部分
-
符号
$!
-
提取最后一次赋值结果
-
-
符号
:
-
+:递归赋值:最后一次赋值
-
+=:递归后再追加
-
:=:立即赋值:不计算,直接赋值
-
?=:条件赋值:只要变量存在,就会赋值
-
-
符号
$@
-
所有目标
-
-
符号
$^
-
所有依赖
-
-
符号
%
-
通配符,匹配指定格式
%.o: %.c
-
-
符号
$(wildcard *.c)
-
获取当前路径下所有
.c
文件
-
-
符号
$(patsubst %.c, %.o, fun.c main.c)
-
将
.c
换为.o
-
-
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 -oall:$(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;}//如果申请空间成功//将堆区申请的一个结构体的空间都清0memset(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语言语言规则。