linux c高级

一、Shell编程基础

1.Shell基础

1.Shell脚本语言是解释性语言,其本质是Shell命令的有序集合

2.shell 脚本以.sh结尾,用bash命令执行(或者./filename.sh),基本格式为:

#!/bin/bash
echo "hello world!"
...

2.Shell变量和环境变量

1.命名规则:Variable=value #中间无空格。eg:count=1

#!/bin/bash
ls -l
#命令置换符``
echo `date`
a=100;
b=200;
#$是取变量取的取值
echo "a="$a
echo "b=$b"

2.Shell变量类型:

用户自定义变量:全部大写,方便识别,加$实现调用。unset命令删除变量赋值。

位置变量(命令行参数):用作函数中参数的传递

#!/bin/bash
echo $0   #$0表示命令行的上一个命令
echo $#   #$#命令行参数个数
echo $1,$2...$9  #表示命令行的1到9个参数,./test.sh 1,2,3..
echo $?  #表示前一个命令的退出状态(0成功,1失败,与c相反)

预设变量:包含环境变量

环境变量:

#!/bin/bash
echo $HOME  #打印用户主目录
echo $PATH  #打印shell的搜索路径(/etc/environment)

3.shell的功能语句

1.shell包括三类

1.说明性语句

注释语句

2.功能性语句

1.read 标准输入读入一行,赋值给后面的参数

#!/bin/bash
read val1 val2 val3
echo $val1 $val2 $val3

2.算数运算指令expr,包括+,-,乘(/*),/,%。算术运算符左右两侧用空格隔开。

#!/bin/bash
expr 23 % 3 /* 4
sum=`expr 12 + 3 \* 5`  #使用命令置换符将这一串命令赋给sum,引用命令的运行结果
expr $sum + $sum
sum=`expr $sum + 1`  #相当于sum=sum+1
echo $sum

3.test 测试对象有字符串,整数,文件属性

#!/bin/bash
read str
test "$str" = "hello world"  #$str为一个字符串可以不加“”,为多个变量是需要加“”
#相等,不等 -eq,-ne
#大于,大于等于 -gt,-ge
#小于,小于等于 -lt,-le
#-d 目录,-f 文件,-s 长度是否为0,-e 文件是否存在,-L 是否为符号链接文件(软链接)
3.shell结构性语句(条件,分支,循环)

1.条件语句:

#!/bin/bash
#条件语句格式
if 表达式
then 命令表1
elif
then 命令表2
else 命令表3
fi
if test -f $1  #或可写成if [ -f $1 ],中括号里为条件
then 
	echo "$1 is 普通文件"
fi

2.多路分支语句:case…esac和switch…case相似

#!/bin/bash
#语法结构
case 字符串变量 in
模式1) 命令表1;;
模式2|模式3) 命令表2;;
...
模式n) 命令表n;;
esac
read a b
sum=0
case $1 in
	1) let sum=a+b;;
	2) let sum=a-b;;
	3) let sum=a*b;;
	*) echo "input error"
esac
echo "sum=$sum"

3.循环语句:

#!/bin/bash
#for语法结构
for 变量名 in 单词表 #单词表可为{1..100}
	do
	命令表
	done
for i in {1..10}
	do
	let sum=sum+i
	done
echo "sum=$sum"

#while语法结构
while 命令或表达式
	do
	命令表
	done
while [ $i -le 10 ]
	do
	sum=`expr $sum + $i`  #let sum=sum+i
	i=`expr $i + 1`      #let i++
	done
	echo "sum=$sum"
	

4.循环控制语句:break,continue

break n 跳出n曾循环

#break n 跳出n曾循环
#continue n  
#!/bin/bash	
num=1
while [ $num -le $1 ]
do
	count=`expr $num % 2`
	if [ $count -eq 0 ]
	then
	num=`expr $num + 1`
		continue
	else
		echo "$num"
	num=`expr $num + 1`
	fi
done

2.shell数组

#!/bin/bash
#shell数组用()表示,数组元素用空格隔开
#$@表示命令行所有参数
#array(元素1 元素2 元素3 ...)
数组定义:
a=(1 2 3 4 5 6) a=($@)
read val   a=($val)
arry=($@)
数组调用
${a[$i]}
${a[@]} #遍历数组
${#a[@]}  #计算数组中元素个数
#!/bin/bash	
arr=($@)
sort ()
{
local arr=$1
for((i=0;i < ${#arr[@]};++i))
do
	for((j=i+1; j < ${#arr[*]};++j))
	do	
		if [ ${arr[i]} -ge ${arr[j]} ]
		then
			t=${arr[i]}
			arr[i]=${arr[j]}
			arr[j]=$t
		fi
	done
done
}
arr=($@)
sort "${arr[@]}"
echo ${arr[@]}

4.shell函数

1.shell函数的定义

函数名()
{
	函数体
}
function 函数名()
{
	函数体
}
注意:函数定义时不能有任何c语言的形参,函数必须定义在调用之前,函数只能在本shell文件中使用
#!/bin/bash
function add()
{
	#expr $1 +$2  函数中的$1,$2不是保存的命令行参数,保存函数传递的实参
	sum=`expr 6 + 5`
	return $sum
}

2.shell函数的调用

#!/bin/bash
add  #函数调用(直接函数名)
#方式1
echo "add return"$?   #$?表示add函数返回的值,$?会保存函数返回值
#方式2
变量名=`函数名 参数1 参数2 参数3`
#注意:函数中没有使用return,而是使用了向终端输出的命令
SUM=`add`
echo "SUM=$SUM"
#!/bin/bash
function add()
{
	sum=`expr 1 + 2`
	return $sum
}
add1()
{
	expr 1 + 2
}
add
echo "return value"$?
sum1=`add1`
echo "sum1=$sum1"

3.函数参数传递

#!/bin/bash
function func()
{
	expr $1 + $2  #函数中的$1 $2等未知变量只能用来保存函数调用时保存的实参
}
read a b
SUM=`func $a $b`  #函数调用时参数传递方式1
echo "SUM=$SUM"
function fun2()
{
	RES=`expr $1 + $2`
	return $RES
}
fun2 $a $b  #参数传递,传递的实参,将会被函数中的$1~$9保存
echo "$a + $b = $?" #函数调用时参数传递方式2

4.局部变量

#!/bin/bash
sum=12
add()
{
	echo "sum:$sum"
	local sum=`expr $sum + 3`  #local声明局部变量
}
add
echo "sum=$sum"

二、c语言的编译工具和调试工具

1.编译工具:将一个源程序编译成一个可执行程序

gcc编译步骤

预处理:将源文件中的头文件,宏定义变量展开替换,生成*.i文件。常用命令:gcc -E *.c  进行预处理;gcc -E *.c -o *.i  将c文件预处理生成*.i文件
分析器(编译处理):检查代码的语法结构,语法错误等。常用命令:gcc -S *.c    gcc -S *.i -o *.s
汇编器(汇编处理):将汇编代码翻译成系统的机器码,生成*.o文件。常用命令: gcc -c *.c -o *.o
链接器(链接处理):目标文件,依赖库文件等链接组成一个可执行文件。常用命令:gcc *.o -o test

2.调试工具 :能对执行程序进行源码或者汇编级的调试(查看)

GDB调试:在使用gcc编译时要加上-g选项才能进行gdb调试

gcc -g *.c -o test
gdb test
查看文件:(gdb)l       
在第n行设置断点:(gdb)b n 
查看断点信息:(gdb)info b
删除断点:(gdb)d 断点号
运行代码:(gdb)r   #遇断点暂停
查看变量n的值:(gdb)p n
单步运行:(gdb)n或(gdb)s
恢复程序运行:(gdb)c  
退出:(gdb)quit或(gdb)q
查看所有变量的值:i locals

三、C语言指针

1.指针基础

1.指针:c语言中,内存单元的地址(编号)。

2.指针变量:存放地址量的变量。

3.指针的目标:指针所指向的内存区域中的数据。

4.指针的目标变量:指针所指向的内存区域。

5.指针定义: 数据类型 * 指针变量名; 在32位系统中所有指针只占4个字节。

char *c;
char ch;
c=&ch;

6.指针运算:算数运算、关系运算、逻辑运算,指针运算的实质是地址量的计算。

7.空指针:NULL

8、野指针:
没有目标变量的指针,野指针的非法使用会造成程序段错误。
野指针的定义:
char *p;
*p += 2; //错误写法,程序段错误,因为 p 是一个野指针
9、数组
1、概念:一串具有相同数据类型的元素的集合。
2、定义:
数据类型 数组名[元素个数];
eg:
int a[10];
1、数组元素下标从 0开始; 数组最后一个元素下标:元素个数 - 1
2、数组的首元素地址就是该数组的首地址;数组的数组名也就是 数组的首地址
3、数组空间大小 = 元素个数 * sizeof(类型)
10、指针和数组
int a[10] = {1, 2, 3, 4, 5, 6};
int *p;
p = &a[0]; //让指针指向数组 a
int *q = &a[0];

1、当一个指针 p 指向数组 a时,则:
	a[i] <==> p[i]	<==> *(a + i) <==> *(p + i)

11、指针数组
概念:
本质上是一个数组,数组中元素全为指针。
定义:
数据类型 *数组名[元素个数];
eg:
int * a[5];

若:	
	char buf[6] = "hello";
	char str[6] = "world";
	char *a[2];		//定义一个指针数组
	a[0] = buf;		//将字符数组buf 存储到 指针数组中
	a[1] = str;		//将字符数组str 存储到 指针数组中
则:
	*(a[i]+j) :取得下标为i的这个数组中第j个元素

若:
	char a[2][6] = {"hello", "world"};
	char *p[2];
	p[0] = a[0];   // ==> p[0] = &a[0][0]
	p[1] = a[1];   // ==> p[1] = &a[1][0]
则 指针数组中的元素就是二维数组的行:
	a[i][j] = *(p[i] + j) = *(*(p + i) + j) = p[i][j]
	
	printf("a[0][0]");
	printf("*(p[0]+ 0)");
	
	printf("a[0][1]");
	printf("*(p[0]+ 1)");	

2.特殊关键字

1.const:常量化,表示被const修饰的变量不可修改

char  * const p;  //const修身指针变量,表示指针变量不可修改,也就是指针的指向不变,	但是可以通过*来修改指针目标的值
char const *p;  //*p不可更改
int const * const p //p,*p都不能修改

2.void型指针:指向一种不确定类型的指针,可通过强制转换

3.malloc:在堆区空间开辟一片内存空间

//函数原型
void *malloc(int nbytes);//在堆区开辟nbytes个字节的空间,返回该空间首地址。头文件  #include <stdlib.h>

4.free:释放堆区空间

//函数原型
void free(void *p);//释放堆区空间
#include <stdlib.h>
#include <stdlio.h>
void main()
{
	char *p;
	//开辟4字节空间,将首地址赋值给p
    p=malloc(sizeof(char *)); //隐式转换
    p=(char *)malloc(sizeof(char *));
	*p+=23;
    free(p);//释放堆区空间,实质是该指针的指向标记清除,断开指针指向,堆区空间还在。
    //一般会给p赋空
    p=NULL;
}

3.函数

1.sscanf()

实际开发中用作数据的提取。

//函数原型
int sscanf(const char *str,const char *format,...)
//功能:从str字符串中,将数据按照format格式,赋值给后面的变量
char buf[]="light:128hum:27temp:26";
int light,hum,temp;c
sscanf(buf,"light:%dhum:%dtemp:%d");

2.sprintf()

实际开发中用作数据的组装。

char buf[128]={0};
int light=125,hum=29,temp=32;
sprintf(buf,"%d",light);  //将int 125赋值到char数组中
sprintf(buf,"%d,%d,%d",light,hum,temp);//以字符的形式存在buf里面
//执行之后buf="125,29,32"

3.、函数、指针函数、函数指针

​ 1、函数:
​ 完成特定功能的代码模块,其程序代码要独立,通常要求有返回值。

2、函数定义的语法结构
	数据类型 函数名(<形参列表>)
	{
		函数体
		return;
	}
	
	注意:
		1、函数的数据类型,就是该函数返回值的类型。
		2、形参列表中多个形参时,以逗号","隔开。也可以没有任何形参
		3、函数也可以没有返回值
		
3、函数的调用
	函数名(<实参列表>);
	变量名 = 函数名(<实参列表>);
	注意:
		1、函数调用时,实参列表被形参列表决定有无
		2、函数调用时,是否保存返回值,取决于调用之后的代码中是否需要返回值
		
4、函数的声明
	一般形式:
		数据类型 函数名(<形参列表>);
		注意:
			1、一般情况函数声明头文件中,也就必须声明在函数被调用之前
			2、函数的声明是没有函数体的,以 ; 号表示声明的结束
			3、函数声明时的形参列表中,形参变量名可以不写,只保留数据类型
			
5、函数参数传递方式:
	1、值传递(复制传递):
		函数调用时,系统将实参的数值,拷贝到函数空间形参中,
		则不能通过形参访问、修改实参的数值。
	2、地址传递:
		函数调用时,系统将实参的地址,拷贝给函数空间的形参中,
		则在函数空间中可以通过形参的数值 访问、修改实参的数值。			
3、指针函数:
		1、概念:
			返回值为地址量的函数,本质还是函数
	2、定义的一般形式:
		数据类型 * 函数名(<形参列表>)
		{
			函数体
			return 地址量;
		}
	3、大部分字符串处理函数都是指针函数
		字符串处理函数头文件:
			#include <string.h>
		1、字符串拷贝
			char *strcpy(char *dest, const char *src);
			char *strncpy(char *dest, const char *src, int count);
			
		2、字符串的拼接
			char *strcat(char *s1, const char *s2);
			
		3、字符串查找
			char *strstr(const char *s1, const char *s2);
			
		4、字符串设置函数
			void *memset(void *buf, int c, int n);
			功能:
				将 buf 地址上的前 n 字节数据设置成 c。
				实际开发中常用来做 字符串的清零,保护数据的安全、完整性。
				
		5、字符串大小比较函数
			int strcmp(const char *s1, const char * s2);
			int strncmp(const char *s1, const char * s2, int n);

4、函数指针

​ 1、概念:
​ 本质上就是一个指针,保存函数地址的指针变量。
​ 函数名就是该函数的入口地址。

2、当一个指针指向函数,那么可以通过该指针,来调用这个函数。

3、定义的一般形式:
	数据类型 (*指针变量名)(<参数列表>);
		eg:
			int (*p)(int, int);

5、函数指针数组

​ 1、概念:
​ 本质上是一个数组,数组中的每一个元素都一个函数指针。
​ 2、一般形式:
​ 数据类型 (* 指针变量名[元素个数])(<形参列表>);
​ eg:
​ int (*p[10])(int, int);

6、递归调用

​ 函数内部自己调用自己。

编写程序实现 5;

	递推阶段:
		5= 5 * 4;
		4!  = 4 * 3! ;
		...
		
	回归阶段:
	
	int func(int n)
	{
		if (n == 1)
			return 1;
		return n*func(n-1);
	}

7.字节序对齐方式sasdASsa

联合体(union)和结构体(struct)都满足字节序对齐,联合体大小是占内存最大的成员按照字节序对齐之后的大小

//一般情况下在32位系统中含有int,double按4字节序对齐,在64位中duble是8字节对齐
//类型字节数最大的字节序对齐
//若开辟空间用不完,则会把其他空间压入,若不能完全存下,则在单独开辟空间。例如:
struct stu1
{
    int age;           //4字节序对齐,开辟4byte字节空间
    char sex;			//开辟4字节空间,剩3byte
    char name[10];		//10个连续的1byte空间,用掉sex的3byte,还剩7byte,4字节序对齐,还得开辟8byte空间
    //sizeof(strcut stu1)=16byte
};
struct stu2
{
    char name[11];//12byte
    char sex;//存入name[11],剩下的1byte空间
    int age;//4byte
    //sizeof(struct stu2)=16byte
};
struct stu3
{
    char sex;  //4byte
    int age;	//存不下,单独开辟4byte
    char name[10];//12byte
    //sizeof(struct stu3)=20byte
};
struct stu4
{
    //2字节序对齐
    char sex;//2byte
    char name[10];//用掉sex的剩余一个,还剩9byte,还得开辟10byte
    short age;//剩余1byte空间,存不下,单独开辟2byte
    //sizeof(struct stu4)=14byte
};
struct stu4
{
    //2字节序对齐
    char sex;//2byte
    char name[9]//用掉sex的剩余一个,还剩8byte
    short age;//开辟2byte
    //sizeof(struct stu4)=12byte
};
union str1     //4byte对齐,16byte
{
    char name[13];
    int sex;
};
//枚举是为了替换多次宏定义,从左往右数字依次增1
//定义之后无法修改
enum week{mon=1,thu,wed,thi,fri,sta,sun};//这样定义默认1~7
enum week{mon=1,thu=3,wed,thi,fri,sta,sun};//这样定义默认1,3~8

关键字
1、extern :引用外部变量,引用外部函数
注意:
1、extern 引用的外部数据,必须定义初始化。
2、extern 修饰的变量,不能进行初始化。
3、一般情况下,extern 用来引用其他文件的变量或者函数。

2、动态内存分配
malloc/free
calloc

3、宏定义: #define
#define Max(a, b) ( (a) > (b) ? (a) : (b) )
宏定义副作用:
Max(++a, ++b); ( (++a) > (++b) ? (++a) : (++b) )
宏定义一个变量,表示一年中有多少秒:
#define second (3652460*60)ul

4、条件编译:
#if Debug
语句1
#else
语句2
#endif

​ 1、如果 Debuf 宏值为0(假值),表示:
​ 语句1被注释(屏蔽),不会被编译器编译;
​ 语句2才会被编译器进行编译。

​ 2、如果 Debug 宏值为1(真值),表示:
​ 语句1倍编译器进行编译,
​ 语句2被屏蔽(注释),不会被编译器编译。

二、make工程管理工具

1、“自动”的工作原理:根据文件时间戳发现新更改的文件进行编译,减少大量的编译时间。
2、Make工程管理工具,根据读入的Makefile文件内容来批量执行编译命令。

3、Make只编译改动的代码文件

4、Makefile变量定义方式:
	1、递归展开式:
		Var=var
	2、简单方式:
		Var:=var
	3、?=   :
		dir := /var/lib
		FOO ?= lib
		(含义,FOO变量如果没有被定义过,则FOO的值为 lib;
			如果定义过就保留原来的值)	
5、自动变量
	1、$< 	:表示第一个依赖文件
	2、$^   :表示所有不重复的完整依赖文件名
	3、$@	:目标文件完整名
6、其他目录下的文件进行编译
	SRCS	 = $(wildcard ./src/*.c ./lib/src/*.c ./lib/cjson/*.c)
	# wildcard		:遍历后面路径下的c 文件,然后保存到 SRCS中
	OBJS	 = $(patsubst %.c, %.o,$(SRCS))
	#patsubst       :将所有的c文件替换成所有的.o文件,保存到OBJS中
	CC = gcc
	all: $(APP)
	$(APP): $(OBJS)
		$(CC) -o $(APP) $^ $(LDFLAGS)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吼哈哟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值