C语言
1. 什么是int main(int argc, char *argv[])
1.1 enum(枚举类型)
2. Valgrind
2.1报告的信息
(1)当前程序(./test1_g)的进程号 (2)valgrind memcheck工具的license说明 (3)加载程序的运行方式 (4)父进程号,当前终端的进程 (5)检测到的错误信息 (6)堆栈摘要、小结,该例子中总共两次alloc、两次free,没有内存泄漏 (7)检测到的错误数量,这里提示1个 原文链接:https://blog.csdn.net/weixin_45518728/article/details/119865117
3. return
3.1 return 0 , return 1 和 return -1
return 1和 return -1不能同时出现在同一个函数中。
return关键字的作用是返回程序流程的控制权!只要使用了retrun,不管有无返回值,都表示该函数调用结束。
return0 代表函数正常终止
return1 代表函数非正常终止
return-1 也代表函数非正常终止。 原文链接:https://blog.csdn.net/jinchi_boke/article/details/115332701
4.一些系统自带的函数
4.1 isalpha
和isblank
isBlank(null)------true isBlank(" ")------true isBlank("\t \n \f \r")------true //制表符、换行符、换页符和回车符 isBlank("a")------false
int isalpha(int c); c -- 这是要检查的字符。 如果 c 是一个字母,则该函数返回非零值,否则返回 0。
4.2 rand()
和srand()
随机数与种子
- rand()函数用于产生一个随机数,其内部实现是用线性同余法实现的,是伪随机数,由于周期较长,因此在一定范围内可以看成是随机的。
- srand()函数产生随机种子。
- 原文
4.3 fscanf
,fprintf
和fgets
- fgets()(函数原型:char fgets(char restrict str, int size, FILE *restrict stream))
fgets()函数的作用可以这么解释:从第三个参数指定的流中读取最多第二个参数大小的字符到第一个参数指定的容器地址中。在这个过程中,在还没读取够第二个参数指定大小的字符前,读取到换行符'\n'或者需要读取的流中已经没有数据了。则提前结束,并把已经读取到的字符存储进第一个参数指定的容器地址中。原文
- fscanf()
int fscanf(FILE * stream, const char * format, [argument...]);
根据数据格式 const char * format , 从文件 FILE * stream 中 , 读取数据存储到 [argument...] 参数中
- fprintf()
int fprintf (FILE* stream, const char*format, [argument])
FILE* stream 参数 : 文件指针 ;
const char*format 参数 : 要写入的文本格式 ;
[argument] 参数 : 文本格式对应的若干参数 , 这是个可变参数 ;
5. 数组与指针
5.1 深入理解char * ,char ** ,char a[ ] ,char *a[]
printf("%s",str);
关键之处为什么用首地址就可以输出字符串。因为还有一个关键,在C语言中字符串常量的本质表示其实是一个地址,这是许多初学者比较难理解的问题。
举例:
char *s ;
s = "China";
为什么可以把一个字符串赋给一个指针变量。 这不是类型不一致吗 这就是上面提到的关键 。 C语言中编译器会给字符串常量分配地址,如果 "China", 存储在内存中的 0x3000 0x3001 0x3002 0x3003 0x3004 0x3005 . s = "China" ,意识是什么,对了,地址。 其实真正的意义是 s ="China" = 0x3000; 看清楚了吧 ,你把China 看作是字符串,但是编译器把它看作是地址 0x3000,即字符串常量的本质表现是代表它的第一个字符的地址。s = 0x3000 这样写似乎更符合直观的意思。搞清楚这个问题。 那么 %s ,它的原理其实也是通过字符串首地址输出字符串,printf("%s ", s); 传给它的其实是s所保存的字符串的地址。
6.内存
6.1 malloc
6.2 calloc
其原型void calloc(size_t n, size_t size); 其比malloc函数多一个参数,并不需要人为的计算空间的大小,比如如果他要申请20个int类型空间,会int p = (int *)calloc(20, sizeof(int)),这样就省去了人为空间计算的麻烦。但这并不是他们之间最重要的区别,malloc申请后空间的值是随机的,并没有进行初始化,而calloc却在申请后,对空间逐一进行初始化,并设置值为0;
6.2 作用域
作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突。
作用域共有:
-
全局作用域
-
函数作用域
-
块级作用域
7.结构体
7.1 示例
#include <stdio.h>
struct student //结构体类型的说明与定义分开。声明
{
int age; /*年龄*/
float score; /*分数*/
char sex; /*性别*/
};
int main ()
{
struct student a={ 20,79,'f'}; //定义
printf("年龄:%d 分数:%.2f 性别:%c\n", a.age, a.score, a.sex );
return 0;
7.2 结构体长度
数据类型的字节数:
32位编译器 char :1个字节 char*(即指针变量): 4个字节(32位的寻址空间是2^32, 即32个bit,也就是4个字节。同理64位编译器) short int : 2个字节 int: 4个字节 unsigned int : 4个字节 float: 4个字节 double: 8个字节 long: 4个字节 long long: 8个字节 unsigned long: 4个字节
7.3 typedef
它是C的一个关键字,可以给其它更复杂的类型起个新的名字。(为用户自定义的数据类型取一个新的名字)
#include <stdio.h>
#include <string.h>
typedef struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
} Book;
int main( )
{
Book book;
strcpy( book.title, "C 教程");
strcpy( book.author, "Runoob");
strcpy( book.subject, "编程语言");
book.book_id = 12345;
printf( "书标题 : %s\n", book.title);
printf( "书作者 : %s\n", book.author);
printf( "书类目 : %s\n", book.subject);
printf( "书 ID : %d\n", book.book_id);
return 0;
}
打印结果
书标题 : C 教程
书作者 : Runoob
书类目 : 编程语言
书 ID : 12345
7.4 strcpy
对字符串进行复制
#include <stdio.h>
#include <string.h>
int main ()
{
char str1[]="Sample string";
char str2[40];
char str3[40];
strcpy (str2,str1);
strcpy (str3,"copy successful");
printf ("str1: %s\nstr2: %s\nstr3: %s\n",str1,str2,str3);
return 0;
}
结果
str1: Sample string
str2: Sample string
str3: copy successful
8. 函数指针
8.1 定义类型与变量
-
指针函数: int p(int, int) 里面的 * 是和前面的 int 在一起的,表示返回值类型是 int
-
函数指针:定义一个指向函数的指针变量
9. C预编译器
9.1 #ifdef
判断某个宏是否被定义,若已定义,执行随后的语句
9.2 特性
##
串联一个参数
关于宏替换的使用原文
9.3 ...与 __VA_ARGS__
在宏定义中,可变参数的部分用__VA_ARGS__表示,实参中对应...的几个参数可以看成一个参数替 换到宏定义中__VA_ARGS__所在的地方。
原文(条件编译与预处理宏)
9.4 extern
和static
-
extern 一个c文件需要调用另一个c文件里的变量或者函数,而不能从.h文件中调用变量
-
static 表示静态的变量,限制此变量作用域在一个源文件内,其他文件不能用extern来引用此变量,不仅适用于变量,函数也可以。
9.5 变参函数
va_list 、va_start、 va_arg、 va_end 使用说明
-
va_start宏,获取可变参数列表的第一个参数的地址(list是类型为va_list的指针,param1是可变参数最左边的参数)
-
va_arg宏,获取可变参数的当前参数,返回指定类型并将指针指向下一参数(mode参数描述了当前参数的类型)
- va_end宏,清空va_list可变参数列表
10. 防御性思维
10.1 八个防御性编程策略
永远不要信任输入
永远不要提供的输入,并总是校验它。
避免错误
如果错误可能发生,不管可能性多低都要避免它。
过早暴露错误
过早暴露错误,并且评估发生了什么、在哪里发生以及如何修复。
记录假设
清楚地记录所有先决条件,后置条件以及不变量。
防止过多的文档
不要在实现阶段就编写文档,它们可以在代码完成时编写。
使一切自动化
使一切自动化,尤其是测试。
简单化和清晰化
永远简化你的代码,在没有牺牲安全性的同时变得最小和最整洁。
质疑权威
不要盲目遵循或拒绝规则。