前序
用来记录C语言学习中的知识点
位运算
- << 表示左移,不分正负数,低位补0
- >> 表示右移,如果该数为正,则高位补0,若为负数,则高位补1
- >>> 表示无符号右移,也叫逻辑右移,即若该数为正,则高位补0,而若该数为负数,则右移后高位同样补0
以>>右移为例,
条件编译
| 指令 | 说明 |
|---|---|
| # | 无任何定义 |
| #include | 引用头文件 |
| #define | 宏定义 |
| #undef | 取消已定义的宏 |
| #if | 条件为真则执行 |
| #ifdef | 存在宏,则执行 |
| #ifndef | 不存在宏,则执行 |
| #elif | 相当于java中的elseif |
| #endif | 结束条件编译 |
#include <stdio.h>
//#define NUM1 10
#define NUM2 20
int main() {
#ifdef NUM1 == 10
printf("sum %d", NUM1);
#elif NUM2 == 20
printf("sum %d", NUM2);
#endif
return 0;
}
理解内存的分配与释放
单链表是动态数据结构,如何开辟一个内存单元呢?通过malloc函数,
(指针类型*)malloc()
返回值为指向新开辟内存单元的首地址
那如何释放内存呢?
通过free可以释放由malloc动态开辟的内存单元,释放后,值是不变的,但是此时内存是无效的,实际例子
#include <stdio.h>
int main() {
int *a = malloc(sizeof(int));
a = 101;
printf("a=%d, length=%d",a, sizeof(a));
free(a);
a = 102;
printf("a=%d, length=%d",a, sizeof(a));
return 0;
}
输出结果为
a=101, length=8
因为此时内存已被释放,所以不能重新赋值了
C语言中的对象-结构体怎么表示
结构体可以可以理解为包含多种不同数据类型的集合,使用方式
struct 结构体名字 {
结构体所包含的变量和数组
} 结构体变量名字
如何给结构体变量赋值
通过.直接引用,类似java对象的引用
#include <stdio.h>
int main() {
struct stu {
char *name;
int num;
char abc;
float score;
} stu1;
stu1.name = "张三";
stu1.num = 101;
stu1.abc = 'A';
stu1.score = 99.6;
printf("%s的学号是%d, 等级是%c, 成绩是%.1f\n", stu1.name, stu1.num, stu1.abc, stu1.score);
}
如何定义结构体数组
以实际demo为例
#include <stdio.h>
struct stus {
char *name;//姓名
int num;//学号
float score;//成绩
} class[] = {
{"zhangsan", 1, 86.2},
{"wangwu", 2, 89.5},
{"zhaoliu", 3, 98.5}
};
int main() {
float total;
int i;
for(i=0; i<3; i++) {
total += class[i].score;
}
printf("平均分为%f", total / 3);
return 0;
}
输出为
平均分为91.400002
C语言中如何回调(待读)
什么是无符号数
C语言的long、short、int默认是有符号的,通过unsigned无符号数,来定义正数,内存减少了一半,不过对应的输出类型要注意,比如int a=10用%d,而unsigned int a = -12,要用%u作为输出
什么是assert断言
assert是<assert.h>的宏定义,用来检查表达式的值是否正确,如果assert内的表达式为假,则终止程序,即不会执行assert后的程序
如何使用
比如
#include <stdio.h>
#include <assert.h>
int main() {
int a = 0;
scanf("%d", &a);
assert(a != 2);
printf("a=%d", a);
return 0;
}
如果输入1,则正常执行,输出结果为
1
a=1
如果输入2,则assert会抛出错误并终止程序,输出结果为
2
Assertion failed!
Program: C:\c_projects\assert.exe
File: C:\c_projects\assert.cpp, Line 6
Expression: a != 2
头文件
头文件是命名为.h的文件,包含函数声明和宏定义,头文件分为系统定义的和用户定义的,
系统定义的通过#include <xx.h>引入,表示只能从系统类库目录中检索,用户自定义的通过#include "xx.h"引入,表示
工程当前目录检索
具体例子实现
先定义头文件header_p.h
#define PI 3.14
#define CONS 2
char *get(char *str, int n);
在test.c中引入,
#include <stdio.h>
#include "header_p.h"
char *get(char *str, int n) {
int a = 10;
printf("str=%s, q=%d\n", str, n*a);
}
int main() {
int a = 6;
get("这是测试", 2);
printf("i=%d,PI=%f", a * CONS, PI);
return 0;
}
输出结果为
str=这是测试, q=20
i=12,PI=3.140000
头文件编译时发生了什么
编译时,并不是分别对两个文件编译,而是将头文件和目标文件合成同一个源代码,然后进行编译
什么是函数指针
一般指针指向整形、字符串等变量,函数指针表示指针指向函数
#include <stdio.h>
int max(int a, int b) {
return a > b ? a : b;
}
int main() {
//函数指针
int (*p)(int, int) = &max;
printf("请输入数字\n");
int d, e, f;
scanf("%d %d %d", &d, &e, &f);
printf("最大的数字%d", p(p(d, e), f));
return 0;
}
main函数
通常main函数中可以不用写参数,但是有种格式为
int main(int argc, char *argv[])
- argc 表示命令行中输入的字符串的数量
- argv[] 表示字符串数组
怎么使用命令行
创建FileTest.c
int main(int argc, char *argv[]) {
printf("please input %d char\n", argc);
for (int i = 0; i < argc; ++i) {
printf("%d arg is %s\n", i, argv[i]);
}
return 0;
}
编译运行FileTest.c,右键选择
然后在terminal中输入
FileTest.exe a b c
字符串和字符数组
- 可以将字符串直接赋值给字符数组
char arr[10] = "this is a string" - 字符串会在最后自动加'\0',所以可作为字符串终止标志
'\0'在ASII码表中是第0个字符,英文名NUL,中文名“空字符”
高级指针
指向指针的指针