Linux C语言编程基本原理与实践

  再学C语言,复习&笔记。

系列顺序: Linux C语言编程基本原理与实践 Linux C语言指针与内存 Linux C语言结构体

更多Linux知识: 一天一点linux


常用指令

sudo管理员权限 sudo apt-get update 更新资源(安装软件前最好先更新资源) sudo apt-get install vim(软件名称) 安装某软件 cd ~ 进入home目录 pwd 显示当前目录路径 ls 显示当前文件夹下所有文件夹及文件 ls -l 进入当前目录的文件夹目录后查看当前文件夹包含的文件/文件夹的类型、创建时间、用户权限、用户和用户组 (最前面是“d”为文件夹;“-”为普通类型的文件) touch + 文件名 新建文件
rm + 文件名 删除文件 mkdir + 目录名 新建目录 vi(vim) + 文件名 使用vim编辑文件 clear 清洁屏幕 cc -v 检查编译器 gcc -v 检查编译器

VIM命令模式: dd 删除整行 i 在光标前面插入 a 在光标后面插入 x 删除单个字符 Shift + a 行尾插入
Shift + i 行首插入 o 下一行插入
Shift + o 上行插入 :$ 跳到代码末尾

第一个Linux C程序

编译文件:

1
cc a.c

会得到a.out 编译文件后查看文件权限: rw-:可读、可写 rwx:可读、可写、可执行 三个rwx 1创建用户 2与创建用户在同一个用户组 3任意用户 运行文件: “.” 当前路径 “./” 当前路径下的文件 执行文件:./a.out

多文件操作

sp max.c 新建max.c文件(窗口打开多个文件) ctrl + w +下箭头 跳转到下一个编辑框 ctrl + w +下箭头 跳转到上一个编辑框 对应行数+d+d 剪切光标下相应行数的程序 9dd(代码占九行,剪切代码) 按p粘贴在剪切板的程序 set nu 打开行号 :wqa 保存所有文件并退出

1
2
3
gcc hello.c -o hello.out  指定编译文件(-o 给编译后的文件重命名)
cp a.c b.c  拷贝文件:将a.c拷贝到b.c
cat a.c 查看源代码程序

分开编译:

1
gcc -c 文件名.c -o 文件名.o

函数可以先编译成.o文件,然后再和主文件一起编译成可执行文件。在源代码多的时候可以提高效率。 例如:

1
2
3
4
5
6
7
8
gcc -c max.c -o max.o
gcc max.o hello.c
./a.out
cp max.c min.c
rm a.out
gcc-c min.c -o min.o 
gcc gcc max.o min.o hello.c
./a.out

gcc编译流程分为4步: 预处理(Pre-Processing) -> 编译(Compling) -> 汇编(Assembling) -> 连接(Linking) 预处理:处理#include、#define、#ifdef 等宏命令 编译:把预处理完的文件编译为汇编程序.s 汇编:把汇编程序.s编译为.o二进制文件 链接:把多个二进制文件.o集合(链接)成一个可执行文件

使用别人的静态库.o文件(机器码,无法查看原代码)可以创建.h文件,然后在源程序中#include<文件名.h>来引用。

hello.c

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#include <stdio.h>
#include "max.h"
#include "min.h"

int main()
{
	int a1 = 33;
    int a2 = 21;
    int maxNum = max(a1, a2);
    int minNum = min(a1, a2);
    printf("%d,%d\n", maxNum, minNum);
    return 0;
}

max.c

1
2
3
4
5
6
7
8
int max(int a, int b)
{
	if(a > b){
    	return a;
    }else{
    	return b;
    }
}

min.c

1
2
3
4
5
6
7
8
int min(int a, int b)
{
	if(a < b){
    	return a;
    }else{
    	return b;
    }
}

max.h

1
int max(int a, int b);

min.h

1
int min(int a, int b);

makeFile的编写与使用

make工具可以将大型的开发项目分成若干个模块。 make工具可以很清晰和很快捷的编译和整理源文件。

rm *.o 表示删除所有.o文件 make -v 检查make版本 vi Makefile 编译修改过的部分 输出文件:源文件 一个tab gcc命令 从上到下逐层求精 eg:

1
2
3
4
5
6
hello.out:max.o min.o hello.c
        gcc max.o min.o hello -o hello.out
max.o:max.c
        gcc -c max.c
min.o:min.c
        gcc -c min.c

最后用make命令执行

重复使用make时,中间生成过的文件不需要再生成,没有修改过的文件不用再编译,会直接跳过该段代码,所以更加节省编译时间。

gcc-c 参数的意义: -c 参数是将源代码编译成“目标文件 .o”,不进行连接 后面多个目标文件可通过-o链接成可执行文件。 不使用这个参数时gcc会直接进行编译链接,生成可执行文件。

main函数详解

1
2
3
4
5
6
# main函数的完整形式
int mainint argcchar* argv[]
{
	printf("hello world\n");
    return 0;
}

gcc main.c -o main.out && ./ main.out echo $? 执行成功则返回0

参数

1
2
3
4
5
6
7
8
9
int main(int argc,char* argv[])
{
    printf("argc is %d\n",argc);
    int i;
    for(i=0;i<argv;i++){
        printf("argv[%d] is %s\n",i,argv[i]);
    }
    return 0;
}

./out.c -l -s asd qwe

输出为:

1
2
3
4
5
6
argc is 5
argv[0] is ./m3.out
argv[1] is -l
argv[2] is -a
argv[3] is asd
argv[4] is qwe

标准输入流输出流以及错误流

cio.c

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#include <stdio.h> //标准输入输出
/*
stdin
stdout
stderr
*/
int main()
{
  printf("hello world!\n"); //输出功能由标准输出流完成,printf是系统封装后的
  int a;
  scanf("%d", &a); //标准输入流,错误流是系统出错的时候的
  printf("input value is : %d\n", a);
  return 0;
}

在输入a.out时,程序执行,系统给程序提供了一个进程,当程序启动时,系统也提供给程序一系列的指针。linux将所有的外设(摄像头,打印机等),都视为文件。当启动应用程序时候,会产生三个文件(stdin,stdout,stderr,即标准输入,输出,错误流)。 默认情况下,输入流就是键盘,stdout默认为显示器,可切换为网卡或者打印机。

1
2
printf("Please input the value a:\n");
fprintf(stdout, "please input the value a:\n");

因为stdout默认是显示器,上两句就是等价的,printf其实就是fprintf封装后得到的。 同理,scanf和fscanf等价:

1
2
scanf("%d", &a);
fscanf(stdin, "%d", &a);

错误流:

1
2
3
4
5
if(a < 0){
fprintf(stderr, "the value must > 0\n");
return 1;
}
return 0;

通过返回值1和0,让程序知道出错了。再次编译cc cio.c -o a2.out,我们运行a2.out,输入2则正常执行,当输入-1,则有对应的提示,即错误流发挥作用。 其实Linux这个很大的系统,就是由这些类似的小工具完成的。当等于0是为正确,错的话为其他值。 标准的输入流,输出流,以及错误流还可以重定向。

Linux几乎可以用于任何领域,这里我们不得不提出linux的通道,管道起到了很重要的作用,不同应用程序之间要配合使用,就需要用到管道。 先说输入流,输出流和错误流的重定向机制:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#include <stdio.h>

int main()
{
printf("input the int value i:\n"); \\printf其实对fprintf的封装,是从标准输出流(即stdout)来输出这个过程
scanf("%d", &i); //默认输入流是键盘
printf("input the int value j:\n");
scanf("%d", &j);
printf("i+j=%d\n", i+j);
}

cc main.c 得到a.out,运行a.out,我们分别输入3和5输入到终端。我们标准输出流是1,输出入是0。 >> 标准输出流重新定向符

1
2
3
./a.out 1>> a.txt   输出到a.txt(默认为1,可不写1
./a.out >> a.txt	内容追加下方
./a.out > a.txt		内容覆盖

执行命令后,分别输入3回车后再输入5。再使用命令cat a.txt,可以看到已经输出到文件里的内容。 错误流重定向:1>标准输出流重定向 2>标准错误流重定向 ./a.out 1>t.txt 2>f.txt 将正确的输出流重定向输出到t.txt,错误的输出流重定向输出到f.txt

<< 标准输入流重新定向符

1
./a.out < input.txt input.txt的内容作为输入流传递给程序a.out

综合使用标准输出流、标准错误流、标准输入流

1
./a.out 1>t.txt 2>f.txt <input.txt  

管道原理及应用

ls / 查看根目录 ls /etc/ 查看Linux默认配置目录 ls /etc/ | grep 关键字符 将etc文件输出到一个管道 |管道 eg. 要查找某个目录下有多少个文件名包含“ab”,可以写

1
ls /etc/ | grep ab

将前一个程序输出流重定向到grep,通过管道得到需要的内容。 ps -e | grep ssh ps查看当前的进程,当前操作系统是否开启ssh进程

管道使用demo

程序avg.c,求任意个数的平均值:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#include <stdio.h>

int main()
{
  int sum, n;
  scanf("%d,%d", &sum, &n);
  float v = sum / n;
  printf("v = %f\n", v);
  return 0;
}

cc avg.c -o avg.out

再写一个统计输入的程序input.c:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
int main()
{
  int flag = 1;
  int i;
  int count = 0;
  int sum = 0;
  while(flag){
    scanf("%d", &i);
    if(0==i){ 
    break;
    }
    count++;
    sum+=i;         
}
printf("%d,%d\n",sum,count);
return 0;
}

cc input.c -o input.out 结合使用以上两个程序,将所有数据进行统计,执行input.out,之后通过管道经过avg.out计算平均值。 ./input.out | ./avg.out 以上就是通过管道,将两个小程序连接起来得到更复杂的程序的过程。

Licensed under CC BY-NC-SA 4.0
最后更新于 0001-01-01 00:00 UTC
使用 Hugo 构建
主题 StackJimmy 设计