有没有新手跟兔子哥一样,学 C 语言时被指针、数组、函数这 “三巨头” 搞得头大?指针的 “*” 和 “&” 绕来绕去,看了半天还不知道指向哪儿;数组明明定义了长度,一循环就越界,程序崩得莫名其妙;函数参数传过来传过去,结果总不对,尤其是在 Linux 下写程序,还得兼顾系统调用,更懵了。别着急,兔子哥当年在 Linux 下写一个简单的文件读写程序,就因为用指针操作文件描述符时没检查返回值,导致程序在服务器上跑一次崩一次,后来才发现是指针指向了无效内存。今天就带大家把这三个核心模块拆透,再啥用、怎么在 Linux 里用、用错了会咋样,全给你说明白,结合实际案例,新手也能看懂,一起往下看吧!
指针:Linux 开发里的 “万能钥匙”,到底是个啥?
基础问题:指针到底是啥?为啥 Linux 开发离不开它?
指针就是存内存地址的变量,跟 Linux 里的文件描述符有点像 —— 文件描述符是存文件在系统里的 “位置”,指针是存数据在内存里的 “位置”。比如
int a = 10; int *p = &a,p就像个标签,贴在a的内存地址上,通过p能直接找到a。Linux 内核里到处都是指针,比如进程控制块(PCB)里的指针链表,用指针串起来进程间的关系;文件操作时,
read、write函数的缓冲区地址,也得用指针传。不用指针,Linux 里的内存共享、数据传递根本玩不转。场景问题:Linux 下怎么用指针操作文件?哪里容易出错?
在 Linux 里用 C 语言操作文件,常常用指针指向缓冲区。比如读文件内容到缓冲区:
c运行
#include #include #include int main() {int fd; // 文件描述符char *buf = malloc(1024); // 申请缓冲区,指针指向它if (buf == NULL) { // 必须检查,不然指针可能是野指针perror("malloc失败");return 1;}fd = open("test.txt", O_RDONLY); // 打开文件if (fd == -1) {perror("打开文件失败");free(buf); // 记得释放,不然内存泄漏return 1;}ssize_t n = read(fd, buf, 1024); // 读文件到buf指向的内存if (n > 0) {printf("读到内容:%s\n", buf);}close(fd);free(buf); // 用完释放buf = NULL; // 避免野指针return 0;}这里的
buf指针指向申请的内存,read函数通过这个指针找到要写入的地方。新手容易忘检查malloc的返回值,要是内存申请失败,buf就是野指针,read会写乱内存,在 Linux 里可能导致程序被系统杀死。解决方案:如果不用指针操作 Linux 文件会怎样?
不用指针的话,就得用数组当缓冲区,但数组长度固定,比如
char buf[1024];,如果文件超过 1024 字节,读不全;想动态调整大小,没指针根本做不到。而且 Linux 的系统调用大多要求传地址(指针),比如execvp函数执行命令,参数必须是指针数组,不用指针连命令都跑不起来。数组:Linux 命令行参数处理的 “主力军”,咋用好?
基础问题:数组在 Linux 里主要干啥用?跟指针啥关系?
数组是存一堆同类型数据的 “盒子”,在 Linux 里最常用的是处理命令行参数。比如你在终端敲
ls -l /home,程序里的main函数就通过数组argv接收这些参数:int main(int argc, char *argv[]),argv是指针数组,每个元素指向一个参数的字符串。数组名其实就是首元素的地址,比如
char arr[] = "hello";,arr和&arr[0]是一个意思,这也是为啥数组能和指针混用 —— 在 Linux 源码里,遍历数组常常用指针,比下标更高效。场景问题:Linux 下怎么用数组处理命令行参数?步骤是啥?
写个简单的程序,接收命令行参数并打印,比如
./a.out 张三 20,打印出参数:c运行
#include int main(int argc, char *argv[]) {printf("参数个数:%d\n", argc);for (int i = 0; i < argc; i++) {printf("第%d个参数:%s\n", i, argv[i]);}return 0;}编译后在 Linux 终端运行,
argv[0]是程序名./a.out,argv[1]是张三,argv[2]是20。处理时要注意argc是参数个数,循环别超过argc-1,不然数组越界,在 Linux 下可能读取到无效内存的乱码。解决方案:如果数组越界处理 Linux 参数会怎样?
在 Linux 里,数组越界访问可能读到栈里的其他数据,比如环境变量,甚至导致程序崩溃。之前兔子哥写过一个处理命令行参数的程序,循环条件写成
i <= argc,结果打印出一堆乱码,后来才发现是越界读到了栈里的环境变量地址。严重的话,越界写操作可能修改函数返回地址,被黑客利用搞缓冲区溢出攻击,Linux 系统对此有严格的防护机制,会直接杀死程序。函数:Linux 系统调用的 “包装器”,怎么封装才好用?
基础问题:函数在 Linux 开发里有啥用?为啥要封装系统调用?
函数就是把一堆代码打包,方便重复用。Linux 里的系统调用(比如
open、write)用起来麻烦,得检查返回值、处理错误,把它们封装成函数,能少写很多重复代码。比如封装一个安全的文件打开函数,自动处理错误:
c运行
#include #include int safe_open(const char *path, int flags) {int fd = open(path, flags);if (fd == -1) {perror("文件打开失败"); // 自动打印错误原因}return fd;}以后用
safe_open代替open,不用每次都写错误检查,省事还不容易忘。场景问题:Linux 下怎么用函数传递数组和指针?要注意啥?
在 Linux 里写函数传递数组,通常传数组首地址(指针)和长度,比如写个函数统计文件内容里的字符数:
c运行
int count_chars(char *buf, int len) {int count = 0;for (int i = 0; i < len; i++) {if (buf[i] != '\0') { // 跳过字符串结束符count++;}}return count;}调用时传缓冲区指针和大小:
int chars = count_chars(buf, 1024);。注意必须传长度,因为函数里没法通过指针知道数组实际长度,只传指针的话,很容易越界。解决方案:如果函数里没传数组长度会怎样?
在 Linux 下,函数不知道数组长度,可能会一直访问到
\0或无效内存,统计字符数会不准,甚至读取到敏感数据。之前有个同事写日志分析函数时,没传数组长度,结果程序把缓冲区后面的密码字符串也统计进去了,虽然没出大问题,但想想都后怕。所以在 Linux 开发里,传递数组必须带长度,这是铁律。自问自答:Linux 下用这三个模块常遇到的问题
“在 Linux 里用指针操作内存,比在 Windows 里更危险吗?”
好像是这样,Linux 对内存管理更严格,野指针写内存可能触发 “段错误(segmentation fault)”,程序直接被杀死,还没提示具体在哪错了。Windows 有时还能跑一会儿,所以在 Linux 里用指针,
malloc后检查NULL、free后设NULL,这些步骤一步都不能少。“数组和指针在 Linux 源码里哪个用得多?”
看 Linux 内核代码就知道,指针用得更多,尤其是链表、树这些数据结构,几乎全靠指针串起来。数组用在固定长度的场景,比如进程状态码、文件描述符表,因为长度已知,用数组更高效。
“封装 Linux 系统调用时,函数参数用值传递还是指针传递?”
简单的整数(比如文件描述符、长度)用值传递,复杂的数据(比如缓冲区、结构体)必须用指针传递。比如
write函数的缓冲区,不用指针的话,得把整个缓冲区的数据复制一遍,太费内存,Linux 里根本不会这么干。结尾心得
指针、数组、函数这三个模块,在 Linux 开发里就像螺丝刀、扳手、钳子,缺一不可。兔子哥的经验是,学的时候别死记概念,多在 Linux 下写小程序练 —— 用指针读个文件,用数组处理命令行参数,把系统调用封装成函数,错几次就明白了。Linux 终端里的
gdb调试工具一定要会用,指针乱指、数组越界,用gdb单步跑一遍,在哪错的一目了然。别害怕段错误,每次错误都是帮你记住规则的机会,练得多了,你会发现这 “三巨头” 其实挺好驾驭,在 Linux 里写 C 程序也会越来越顺,加油!版权声明:除非特别标注,否则均为本站原创文章,转载时请以链接形式注明文章出处。
还木有评论哦,快来抢沙发吧~