前言
在之前的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
第三版
变量定义和初始化
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 -o
all:$(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 -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语言语言规则。