学习笔记3:Linux C语言编程基本原理+指针与内存
编程基本原理与操作
单文件编译
gcc -s a.c //生成汇编语言文件.s
gcc -c a.c //生成静态库文件.o
gcc a.c //生成可执行文件.out
//生成可执行文件,但会报warning
多文件编译
-
函数单独写入"max.c"文件,在"hello.c"文件里面加语句
#include "max.c"
,一起编译即可 -
函数头文件分离
输入gcc a.o b.o hello.c -o hello.out
生成可执行文件,但会报warning:
此时需要加入函数声明int max(int a, int b)
,即可。
但是这样的话,同事并不知道当前的c文件到底要和哪些.o文件一起被编译,所有可以写一个.h的头文件,改头文件里都是函数声明,在住文件中加入#include <min.h>
即可
Makefile的使用
注意Tab,不可以被6个空格或者8个空格替代,输入make
,即可自动编译生成对应的所有文件
- vim 编写的一些命令:
ctrl + w + 下键/上键 //切换窗口
:sp b.c //同时打开b.c文件
:set nu //打开行号
:wqa //退出并保存所有文件
main函数详解
main函数完整形式:
int main(int argv, char *argc[]){}
主函数的代码为printf("argv = %d\n")
,输入./main.out
,打印argv的值为1;输入./main.out -l
,打印argv的值为2。
输入流 stdin,输出流 stdout,错误流 stderr
./a.out
./a.out > a.txt //将输出重定向到a.txt,覆盖
./a.out 1>> a.txt //将输出重定向到a.txt,追加
./a.out >> a.txt //将输出重定向到a.txt,追加
./a.out < a.txt //将输入流重定向到a.txt
管道
其中,| 表示管道,grep是文本搜索, ab是文本搜索的内容
ls /etc/ | grep ab //把前一个命令的输出流 作为第二个命令的输入流
./input.out | ./argv.out //将第一个的输出作为第二个的输入
指针与内存相关知识
GDB 调试
gdb -g main.c -o main.out //重新编译 ,生成可以被调试的文件
gdb main.out //开始调试
l
p 变量名称
bt //backtrace,查看函数调用信息(堆栈)
f 0 //frame,查看栈帧
start
quit
n
s //单步进入
x/3d 0xfffffff //从0xfffffff开始按十进制输出连续的三个地址内容,默认间隔为4字节
内存管理
-
32位操作系统最大使用4G内存,因为地址总线是32位,即寻址空间是32位。
-
地址总线 :有32位,可产生有232种状态,232 = 210 * 210 * 210 * 22 = 1024 * 1024 * 1024 * 4 = 4G
-
操作系统:对所有的内存条进行编号,编号=唯一的内存字节的地址,一个字节地址存放8bit数据。由于内存的使用不确定,应用程序由操作系统来调用,并对内存做规划。对于64位的操作系统,只分配前48位给程序员,剩下的给操作系统内核。
-
代码段:
函数编译后存到磁盘,代码编译后的二进制数据保存加载到内存中的代码段 -
数据段:
声明的全局变量和常量放在数据段 -
栈:
经常能够听到函数栈的说法
当前调用哪个函数
函数的参数
当前调用的函数运行到多少行
并且这个函数中有哪些变量,这些变量的值是什么(局部变量) -
堆:
存放new或malloc出来的对象
变量和指针的本质
变量名只是一个代号,变量的本质就是内存,指针保存的是内存的地址int *pa = &a
。
main()函数里面声明的变量在栈里面。
int类型占4个字节,注意,GCC编译时,会先统一给所有int类型变量分配地址,再是double。。。本处因为是64位机器,故指针占8个字节。
- 函数指针
声明方式:int (*pfunc_name)(int m, int n) = func_name;
调用方式:int s = (*pfunc_name)(_m, _n);
数组
- 指针运算
考虑指针偏移,效率很高,比总线查找地址要快很多。
int *p = &a;
p += 3; //默认指针偏移三格
- 字符数组与指针字符串
打印发现str2是“world”存储的地址,是一个很小的值,在代码段。
若读取的ss长度大于10,会一直覆盖后面的内容:
char ss[10];
scanf("%s", ss);