printf
。
https://www.2048.org 这是一个2048 我们可以将其分解为以下几个模块
run_game() {
initialize_board();
generator_number(); generator_number();
while (true) {
switch (choose_direction) {
case UP: move_and_merge_up();break;
case DOWN: move_and_merge_down();break;
case LEFT: move_and_merge_left();break;
case RIGHT:move_and_merge_right();break;
}
is_finished() ? break:;
generator_number();
print_board();
}
}
typedef unsigned char uint8_t;
类型 | 描述 | 例子 |
---|---|---|
char | 8位,ASCII | ‘a’, ‘A’, ‘\n’, 12 |
int | 整数值(正、负、0),>= 16 位,一般为32位 | 0, 78, -217, 0x2E |
unsigned int | 整数值(正、0) | 0, 6, 35102 |
short | 整数值(正、负、0),>= 16 位,一般为16位 | 0, -8, 32767 |
long | 整数值(正、负、0),>= 32 位,一般为32位 | 0, 78, -217, 301713123194 |
const int integer = 100;
const double dob = 1.20;
const char MyChar = 'c';
integer = 120;
看看会发生什么。#include <stdio.h>
int main(int argc,char* argv[]) {
const int intager = 100;
const double dob = 1.20;
const char MyChar = 'c';
// 你可以在此处添加代码
printf("intager:%d\ndob:%lf\nMyChar:%c\n",
intager,dob,MyChar);
return 0;
}
语句(statement)可以是代码块 {} 或只是一个独立的语句
if (expr) statement
if (x == 0) y++;
if (x == 0) {y++;}
if (x == 0) {y++; j = j + y;}
if (expr) statement1 else statement2
while (expr) statement
for (initialize; check; update) statement
https://godbolt.org/z/rzo6o1bsE
#include <stdio.h>
int main(){
unsigned char temp[10] = {0x11,0x15,0x22};
printf("temp address: %p\n",temp);
temp[3] = 0xa8;
for (size_t i=0;i<10;i++) printf("%02x ",temp[i]);
printf("\n");
return 0;
}
'\0'
结束。<string.h>
标准库进行更多操作。https://godbolt.org/z/3jrrvchE1
#include <stdio.h>
#include <string.h>
// 字符串以\0结尾
int main(){
char str1[] = "I Can Eat Glass";
char str2[20] = "I Can Eat Glass";
printf("str1:%s\nsize:%lu\nstr2:%s\nsize:%lu\n",\
str1,strlen(str1),str2,strlen(str2));
}
使用sizeof
和strlen
都能获取字符串长度,它们有什么区别呢?
#define
是文本替换,比如 #define MAX 1000
https://godbolt.org/z/aMPxbrMbs
gcc -o test test.c -save-temps
关于这块,比较好玩的就是微软早期路径长度在编写时使用了宏定义
#define MAX_PATH 260
导致最长路径除了”C:\”之外,只能有255个字符来指代路径了,虽然现在支持在注册表里面进行更改,不过会引发一些神奇的小bug,这个就留给大家进行探索了
C 源文件在编译器看到代码之前首先经过预处理器 CPP
CPP 用单个空格替换注释
CPP 命令以“#”开头
- #include "file.h" / 将 file.h 插入到文件 /
- #include
使用 gcc 的 –save-temps 选项查看预处理结果 完整文档位于:http:// /gcc.gnu.org/onlinedocs/cpp/
unsigned int a = 1;
int b = -1;
float c = 1.5f;
变量可以被分为四个部分: int :类型 b :标识 -1 :值 &b :地址
int array[5] = { 1, 2, 3, 4, 5 };
array 这个标识符是什么呢?
问:能不能访问array[5]呢?
int array[2][2] = {{1,2},{3,4}};
matrix的类型: int[2][2] sizeof matrix = sizeof(int) * 2 * 2
https://godbolt.org/z/Mbq513KnG
(问:下面哪种写法是正确的?)
int matrix[][2] = {1,2,3,4};
int matrix[2][] = {1,2,3,4};
指针也可以看作一个变量,我们对其的定义是这样的
int a = 1;
int* p = &a;
int : int表示指针指向的元素类型 代表的是我要定义一个指针 p : 标识符 &a : 指针的值(指针指向的地址) &p : 存放指针的地址
int* p;
*p = 1; // 危险,p是野指针
应该这么做
int* p = NULL;
当要使用指针指向的值的时候,可以对指针进行解引用
int a = 1;
int* p = &a;
*p = 2;
printf("%d",*p);
// p1的类型是int* , array的类型是int[10]
int array[10];
int *p1 = array;
// p2的类型是int*[2] , matrix的类型是int[][]
int matrix[2][2];
int (*p2)[2] = matrix;
数组与其元素类型的指针存在隐式转换,指向数组首元素的指针可通过数组类型表达式初始化。
问:二维数组可以和二维指针相互转化吗
int array[2][2];
int** ptr = array;
//可以这么做吗
前文提到const就像一把锁,被它锁到的事物不能被更改
int a;
// 锁住指针p指向的int类型变量
const int *p = &a;
// 锁住指针本身,但指针指向的元素可以修改
int const *p = &a;
// 一起锁
const int const *p = &a;
假设你有一段音频文件,你想要进行播放,那你绝对不想播放器修改你的音频,那你可以使用const来设计函数,这样就绝对无法更改了
void wav_player(const int *ptr);
加、减 加、减整数n -> 指向后/前第n个元素
指针相减 表示指针之间的偏移量
仅当原指针和结果指针都指向同一数组中的元素,或该数组的尾后一位置,行为才有定义。
我们很多时候需要警惕未定义行为,就比如说
a[i] = ++i +1;
i在这里多次使用且数值发生了改变,没人知道a[i]先执行还是++i先执行
// i=0
int a = f(i++)+f(i++)-f(i++);
虽然在最后的结果上编译器会将其翻译为int a = (f(i++)+f(i++))-f(i++); 但没人知道哪个f(i++)最先执行,可能是第一个,也可能是第三个
详情请参考 https://zh.cppreference.com/w/c/language/behavior https://zh.cppreference.com/w/c/language/eval_order