int main(int argc, char * argv[]) {
printf("参数个数: %d\n", argc);
for (int i = 0; i < argc; i++) {
printf("%s\n", argv[i]);
}
};
// 单行
/* 多行
*/
- size_t 一般是8字节的无符号整数
- char 1字节
- unsigned char 1字节
- range 一组数据
{0, 1, 2, 3}
int a = 052; // 八进制, 所以是42
int a = 0x12; // 十六进制;
- int 4字节(根据系统而定)
- long 8字节(根据系统而定)
- float 只能保留7位小数(根据系统而定)
- double float
- long double
链接
局部变量的初始值是不确定的. 但是全局变量的初始值默认是0(估计是因为全局变量的值写入了elf)
int a; a 的值不确定哦 // 10亿次需要2.076秒,快了大概3%
int a = 0; a 确定是0 // 10亿次需要2.143秒
int a, b, c;
a = b = c = 4; // 可以同时赋值
int var; 声明并初始化var, 申请了变量的内存地址
extern int var; 仅仅声明, 不需要编译器申请内存
- 寄存器变量
register int a; // a保存在寄存器里, 不保证, 只是个hint
- static变量
static int a; // 变量只能被当前文件访问
另外一个好处是, 函数内的static, 运行完毕后不会被销毁. 所以全局静态变量可以放在函数内部. 并且这个变量只会被初始化一次
int increment() {
static int a = 1; 必须赋予一个constant value, 不能等于一个变量
a++;
return a;
};
- const常量
#define NAME value // 但是这样会导致所有用的地方都赋值一份到内存吧
const value
struct Student *p; // 定义结构体的指针
p = &student
p + 1 // 这样会直接增加strudent的size
- 指针的优先级
[]
优先级比*
高
int *ptr[10]; ptr是个数组(长度为10), 里面每个元素是int的指针
int (*ptr)[10]; ptr是一个指针(数组第0个元素), 每个元素都是int
- 函数的指针
int add(int a, int )
{
return a + b;
}
int (*f)(int, int) = &add; // 实际上有没有&都可以, 因为编译器知道函数名是没有值的, 只有地址
*f(1, 2) // 实际上*有没有都可以, 因为f本身指针不支持执行函数, 所以没有语义歧义
p->age; // 获取p对应的student的age
- sizeof(int/a/a[0])
unary operator, 不是函数哦, 里面的值不会被计算(除非是数组变量)
返回占用内存字节大小
int i = 1;
printf("%d\n", sizeof(i++)); // i不会被+1哦
printf("%lu", sizeof(1));
>>> 4
- 赋值
#include <string.h>
strcpy( Student.name, "ramwin");
函数默认返回的是int. 所以哪怕不声明(declaration)函数, 也能编译成功. 但如果函数最后返回char, 就会报错
- 定义 definition 完整的实现的代码
- 访问
char a[] = {'a', 'b', 'c'}
a[1], *(a+1), 1[a], 都是b哦
- 字符数组
char a[6];
char a[6] = {"s", "t", "r", "i", "n", "g} // 有人说最后要加\0, 但是我字符串都固定长度了,最后不需要加\0了吧。
print("%s", a) // 只会输出 string,试了好多次,总觉得是gcc在最后默认加\0了, 测试验证,的确是的 a[6] 总是0, a[7]是随机。那不就内存不安全了吗,经过测试,应该是超过程序自带的内存就报错,否则是返回真正的内存的?
print("%lu\n", a[50]) // 总是不报错并且返回一个数字
print("%lu\n", a[5000]) // 有可能因为内存不够超过范围而报错
- 初始化
int arr[100]; // 不初始化, 不保证是0
int arr[] = {[0]=1, [5]=2}; // 默认长度就是6
int arr[] = {1, 2, 3} // 不设置长度, 就是3
int arr[] = {1, 7, 5 [5]=90, 6, [8] = 5}; // [5]=90, 那么6就是这是在[6]上的
int arr[] = {1, 2, 3, [2] =4, [6]=45}; // 冲突时, 行为未定义, 不要这么写
int arr[y] = {...}; // error, 边长数组不能初始化
int a[3][2] = { // 注意前面是行数, 后面是列数
{1, 2},
{3, 4},
{5, 6},
}
struct { // 可以不设置struct的name, 直接使用
char *engine;
int fuel_tank_cap;
} car1, car2;
struct Person {
char name[30];
int age;
int id;
};
int main() {
struct Person person = {"张三", 18, 1};
struct Person person2 = {
.name = "张三", .id=3, .age=18}
printf(person.name);
return 0;
};
- 定义
#pragma pack(1) // 使用pragma pack(1)使得结构体不四字节对其
struct abc {
char a;
int b;
char c;
}
struct Person person = {"张三", 18, 1}; // 可以按顺序设置
struct Person person2 = { // 可以按照属性设置
.name = "张三", .id=3, .age=18}
- 结构体必须手动初始化, 只有全局变量才会自动初始化
#include <stdio.h>
struct Student {
char a;
int b[1000000];
char c;
};
void f() {
struct Student c;
printf("字符是: %c end", c.c);
printf("字符是: %d end", (int)c.c);
// 字符是: end字符是: 0 end字符是: a end字符是: 97 end 栈内存不会自动清零
c.c = 'a';
};
int main() {
f();
f();
};
struct Person a;
struct Animal *f = (struct Animal *) &a;
- 如果强制访问超内存的结构体
测试
这样会导致结构体访问的内存不再是属于程序, 如果内存没有超过, 会导致误修改其他变量
int a = 0;
int b = 18;
struct Person *person;
person = &a;
person->age = 32; // b会变成32
- union的类型可以有名字或者没有名字. 如果没有名字, 就要保证元素名都不相同
#include <stdio.h>
struct store {
union {
struct {
int time;
int price;
} book;
struct {
int price;
int time;
} movie;
struct { // 这个结构体没有名字, 直接通过ab访问. 只要不出现 book 或者 movie 就行
int a;
int b;
int price; // 可以和movie内部的元素重名
};
} item;
} s;
int main() {
s.item.book.price = 1998;
printf("%d\n", s.item.movie.time);
printf("%d\n", s.item.b);
};
atomic_int a
a ++; 这样的a可以被多线程进行操作. 同时拿到的值也是不一定的
- scanf
int var, varb;
scanf("%d%d", &var, &varb); # 遇到space才输入, 所以可以输入"123 456\n" "123\n456\n"
char a[10];
scanf("%9s", a); 可以指定输入9个字符
- gets 获取整行输入, 这个已经弃用了. 用fgets
char a[10];
gets(a);
- fgets
注意, 后面的size参数包括了null, 所以只能接受3个字符. 并且会把回车的
\n
也输入进去
char a[4];
fgets(a, 4, stdin); // ab\n
a = {'a', 'b', '\n', '\0'}
puts输出字符串时,会自动添加换行符
char *s = "hello";
puts(s);
printf格式化
输出并会返回输出内容的长度
printf("%lu", <32位无符号整数>) // 但是lu也能显示超过32位的,怀疑有兼容
printf("%llu", <64位无符号整数>)
printf("%s", <字符串>)
-
%u: 无符号整数(short或者int)
-
%d: 整数, short int
-
%p: 地址
-
%c: 字符
-
%f: 浮点数, %.2f 必定保留2位小数
-
%s: 字符串, %10s 必定保留至少10的宽度(前面加空格)
%6.5s
6代表输出占用6个字符宽度, 5代表只读取字符串前5个字符 -
%o: 八进制数字
-
%x/%X: 十六进制数字(会根据x或者X变化大小写)
- lvalue: 存在identifiable location in memory的object 所以必须是变量. 不能是expression, function, const
- rvalue: 不存在identifiable location 表达式, 函数, 常量
- comma operator
计算所有的操作, 但是只返回最后一个
int a = (3, 4, 8), 所以a=8
需要2个operand的操作
+, -, *, /, %, &&, ||, ==, !=, <=, >=, <, >
- logical operators
当前面的计算已经得到结果时, 后续的判断就不会再运算
- &&, || & bitwise and
- &, |, ^
++, --, 必须作用于lvalue
++a, pre-incrementing, 先加后用
a++, post-incrementing
~, not, 所有bit取反
- assignment,
=, +=, *=
- comma
,
顺序最低
Associativity只有在同时存在2个operator才有效果
a = func1() + func2(); 因为这里只有一个operator, 所以不会进行associativity的判定. 所以不能保证func1一定先执行
- 用法
switch(x) { // x或者x的结果必须是整数. 因此case后面的值也必须是整数
case 1: // case后面不能是变量
xxx;
break;
case 2: // case不允许重复
xxx;
break;
default: // default可以放在任何位置
xxx;
break;
}
- 原理
switch (a) { // 先通过a和各个数字比较, 判断jump到哪个命令
1138: 83 7d fc 01 cmpl $0x1,-0x4(%rbp)
113c: 74 08 je 1146 <main+0x1d>
113e: 83 7d fc 02 cmpl $0x2,-0x4(%rbp)
1142: 74 08 je 114c <main+0x23>
1144: eb 0c jmp 1152 <main+0x29>
/home/wangx/test.c:8
case 1:
a+=1;
1146: 83 45 fc 01 addl $0x1,-0x4(%rbp)
/home/wangx/test.c:9
break; // 没有Break的话,就无法跳出了
114a: eb 0b jmp 1157 <main+0x2e>
/home/wangx/test.c:11
case 2:
a+=2;
114c: 83 45 fc 02 addl $0x2,-0x4(%rbp)
/home/wangx/test.c:12
break;
1150: eb 05 jmp 1157 <main+0x2e>
/home/wangx/test.c:14
default:
a+=3;
1152: 83 45 fc 03 addl $0x3,-0x4(%rbp)
/home/wangx/test.c:15
break;
- while
while(expression)
{
Statements1;
Statements2;
}
- for
- do while loop 当你的循环至少需要执行一次的时候,请用do while loop
do {
Statements1;
Statements2;
} while (expression);