数组变量可以当成指针使用, 但有不同的地方:
1. sizeof(数组) 是数组的大小, 而用在指针上返回4或8
2. &数组变量 == 数组变量, 而&指针不同
3. 数组变量并没有分配存储空间, 所以不能指向其它地方
scanf()的用法可参考printf()的用法, 需要设置长度, 例如字符数组, 需要减1, 留给\0, 避免缓冲区溢出, 对于字符串更好的是用fgets(),
配合sizeof运算符使用 备注 scanf -> scan formatted
char指针设置为字符串字面值, 确保使用const关键字: const char *s = "some string"; 因为字面值是不可修改的
---------------------------------------------------------------------------------------------------------------------------------------------------:-)
熟悉使用string.h标准库, 处理字符串
---------------------------------------------------------------------------------------------------------------------------------------------------:-)
使用小工具:
程序结束时检查错误状态: UNIX用 echo $? windows用 echo %ERRORLEVEL%
进程有标准输入和标准输出, 标准错误 stdin, stdout, stderr
当调用printf()时, 其实是调用了fprintf()函数的特殊 fprintf(stdout, "我喜欢乌龟!");
可以用fscanf()来读取标准输入, 用法和scanf()很像
可以用2>重定向标准错误
----------------------------------------------------------------------------------------------------------------------------------------------------:-)
符号 | 表示管道(pipe), 它能连接一个进程的标准输出与另一个进程的标准输入
例如: (./bermuda | ./geo2json) < gpsdata.csv > output.json 数据流由管道从左到右流动
除了标准输入, 标准输出, 标准错误, 还可以自建数据流. 使用fopen()函数
FILE *in_file = fopen("input.txt", "r");
w = 写; r = 读; a = 追加 (注意, 全是小写, 按照书上的例子, 不小心大写了, 运行时报"段错误")
创建数据流后, 可以使用fscanf()函数读数据, fprintf()函数写数据
使用完后需要关闭流: fclose(in_file);
如果出现错误, fopen()会返回0, 最好检查一个有没有错误发生!
----------------------------------------------------------------------------------------------------------------------------------------------------:-)
int main(int argc, char *argv[])
可以向函数传递参数, 前面参数个数从程序本身算起; 后面是char指针数组, 实际也就是字符串指针数组的意思
熟悉POSIX库中的unistd.h头文件中的函数getopt(), 用于处理命令行选项(即以"-"开头的命令行参数)
----------------------------------------------------------------------------------------------------------------------------------------------------:-)
创建头文件只需要在目录中新建.h文件, 写上内容, 保存, 在程序的开头加上预处理命令#include "xxx.h"
注意引号是相对路径查找头文件, 而尖括号是绝对路径查找头文件, 函数声明通常放在头文件中
头文件的作用: 一是函数顺序问题; 另一个是共享代码, 到编译后期链接时有用
共享变量: 在头文件中声明, 在使用时加上extern, 例如: extern int passcode;
----------------------------------------------------------------------------------------------------------------------------------------------------:-)
gcc -c *.c 此命令会为所有源文件创建目标文件, 但不会链接成完整的可执行文件
gcc *.o -o launch 然后, 把目标文件链接起来
总结来说, 如果只修改了一个文件, 只需要重新编译这一个文件, 再重新链接成程序即可
make是如何自动化代码的构建过程的:
写出Makefile文件, 描述目标,依赖项和生成方法, 再用命令make launch
其实原理非常简单, 只是要使用才能记住, 不然明天就忘得一干二净:-)
----------------------------------------------------------------------------------------------------------------------------------------------------:-)
为结构变量赋值相当于叫计算机复制数据
嵌套的结构, 在初始化数据时, 要使用多层花括号的写法
可以使用typedef为结构(/类型)创建别名, 就可以当成类型名使用, 其实只写类型名, 结构名省略, 编译器也没有意见:-)
对了, 这样的话叫做匿名结构哦, 其实也没啥
要更新结构的值, 需要传递结构的指针, 而且可以使用简洁易阅读的语法更新字段: t->age 代表 (*t).age
注意, 上面是指针时用->, 非指针的情况下, 还是要用.号访问字段的!
联合: 声明后设置它的值常用方法 C89方式 quantity q = {4}; 它会设置联合的第一个字段的值
指定初始化器方法: quantity q = {.weight=1.5};
"点"表示法: quantity q; q.volume = 3.7; 这里使用了分行
c语言的位字段: typedef struct { unsigned int lowPassVcf:1; } 必须是unsigned int, 表示该字段只占用一位存储空间
也即是说C语言的位是可以自定义的, 1位或多位空间占用
----------------------------------------------------------------------------------------------------------------------------------------------------:-)
如果一个结构包含一个链向同种结构的链接, 那个这个结构就被称为递归结构.
另外递归结构要有名字, 因为里面有个相同类型的指针, 而C语言的语法不允许用typedef别名来声明它.
在C语言中, NULL的值实际为0, NULL实际专门用来把某个指针设为0
申请存储器(堆空间)的函数叫malloc(), 是memory allocation (存储器分配的意思), 通常与sizeof运算符一起使用
malloc(sizeof(island)); 当然需要头文件 #include <stdlib.h>
malloc()返回通用指针(void*类型), island *p = malloc(sizeof(island));
用完需要调用free()函数释放存储器: free(p);
注意, 使用strdup()之后, 也要调用free(), 因为它通常调用了malloc(), 这要看标准库是如何实现的
堆之所以叫做堆: 计算机不会自动组织它, 它只是一大堆数据而已
可能安装valgrind来检测是否存在内存泄漏, 加上选项, 并把程序传给valgrind
valgrind --leak-check=full ./spies
当然, 可以在可执行文件中加入调试信息, 记录要编译代码的行号 -g 开关
gcc -g spies.c -o spies
----------------------------------------------------------------------------------------------------------------------------------------------------:-)
在C语言中, 函数名就是指身函数的指针, 有了函数指针, 就能把函数传给函数
但还是需要一个函数指针变量: 返回类型 (*指针变量)(参数类型)
例如: char** (*names_fn)(char*, int) 多个参数用逗号隔开
函数指针使用中, 省略* 和&, 编译器也能识别它们, 而且更好读
names_fn = album_names;
char** results = names_fn("Sacha Distel", 1972);
char** 并没有打错, 这是一个指什, 通常用来指向字符串数组
qsort()函数来自于标准库stdlib.h, 用于排序, 接收指向比较器函数的指针, 比较器函数可以比较两个值的大小
比较器函数接收2个指针, 分别指向待排序数组中的两项
函数指针数组写法: 返回类型 (*指针变量)(参数类型) 例如: void (*replies[])(response);
函数指针数组为调用一些相关函数提供了方便, 让代码易于管理和扩展, 从而可以伸缩.
参数可变的函数就称为可变参数函数, 需要包含stdarg.h, 函数写法固定如下
double total(int args, ...) { double total = 0.0; va_list ap; va_start(ap, args); int i; for (i = 0; i < args; i++) { enum drink d = va_arg(ap, enum drink); total += price(d); } va_end(ap); return total; }----------------------------------------------------------------------------------------------------------------------------------------------------:-)
通常类UNIX操作系统会在 /usr/local/include 和 /usr/include 目录查找头文件
只要头文件在标准目录中, 就可以使用尖括号包含它们: #include <stdio.h>
也可以使用完整路径名: #include "/my_header_files/encrypt.h"
也可以告诉编译器去哪里找头文件: gcc -I/my_header_files test_code.c ... -o test_code
用完整路径名共享.o目录文件, 跟指定头文件所在路径差不多写法
只要创建目标文件存档, 就可以一次告诉编译器一批目标文件(应该就是说的压缩包吧:-)
用ar 命令创建存档: ar -rcs libhfsecurity.a encrypt.o checksum.o
r表示存在就更新, c表示创建时不显示反馈, s表示要在开头建立索引, 后面是存档文件名, .a文件
务必把存档命名为libXXX.a, 否则编译器找不到它们, 存档是静态库
nm命令可以查看存档中的内容, 它列出存档中保存的文件的名字: nm libhfsecurity.a
另外 ar -t 文件名 会列出存档中的目标文件
ar -x libhfsecurity.a encrypt.o 该命令可以从存档中提取文件
当存储安装到标准目录: gcc test_code.c -lhfsecurity -o test_code
其它目录: gcc test_code.c -L/my_lib -lhfsecurity -o test_code
由上面笔记及练习题指明: -I 用于指定头文件所在 -L用于指定存档文件所在 如果在当前目录, 后面跟点 .
----------------------------------------------------------------------------------------------------------------------------------------------------:-)
创建动态链接库
创建目标文件 gcc -I. -fPIC -c hfcal.c -o hfcal.o -fPIC意思是创建位置无关代码(事实上不加也没关系)
-shard选项告诉gcc把.o目标文件转化为动态库, 一个平台一个叫法, 然后扩展名也不同, 如上图
Linux叫共享目标文件, 里面还保存了库名, 所以编译后不能修改文件名, 除非重新编译
不同操作系统寻找动态库的方式并不相同, 有点复杂, 在Linux中, 通常保存在/usr/lib或/usr/local/lib中
不知道为何, 当动态库放在标准目录中, 还是不能运行程序, 试了好久, 网上查也没有解决:-(
经过不懈努力, 终于找到了, 原因是我装的64位Linux(CentOS7), 相应需要把动态库拷贝到lib64目录中,Yes! Cool!
而在Window中, 通常把.dll和可执行文件放在同一个目录
在Linux中, 需要设置LD_LIBRARY_PATH变量, 这样程序才能发现动态库
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/libs 这里libs是共享目标文件所在目录, 上图是放在这个libs文件夹, 所以
下面是编译和链接程序命令
gcc -I. -c elliptical.c -o elliptical.o
gcc elliptical.o -L. -lhfcal -o elliptical
----------------------------------------------------------------------------------------------------------------------------------------------------:-)
操作系统内核管理进程, 存储器, 硬件, 而系统调用是程序用来与内核对话的函数
system()函数, 操作系统解释命令, 然后才运行
标签:文件,gcc,头文件,函数,读书笔记,------------------------------------------------------------- From: https://www.cnblogs.com/captionAmazing/p/17471483.html