C

int a //变量声明并定义
extern int a; //显式声明

vs快捷键


ctrl+k +f 自动格式化代码
+k +c   注释代码
+k +u   取消注释代码
F9  设置断点
F5  调试运行
Ctrl+F5 不调试运行
Ctrl+Shift+b 编译不运行
F10 next调试
F11 step调试

vs的4996
define _CRT_SECURE_NO_WARNINGS //防止4996

cpu寄存器内存硬盘之间的关系

CPU通过管脚和内存相连, 管脚里面包含地址总线和数据总线,总线就是一根线, 数据要传数据,地址要寻址

寄存器:寄存器是CPU和内存之间的桥梁。cpu操作速度非常快,内存读取要比cpu慢多了。为了调和CPU和内存的速度差,所以有了寄存器,寄存器是在CPU内部,CPU和内存之间的临时区域,先把内存的数据那一块分到寄存器概念,CPU从寄存器操作,可以满足CPU速度。 (寄存器是64位,而总线只有32位,性能则提升不上去。) 高速缓存存储器:也就是所谓的一级缓存,二级缓存,三级缓存。集成在CPU上

内存最小存储单位 二进制位

一位二进制位只能存放0或1,在物理存储中 0 低电平 1 高点平 1b 等于 一位二进制位 1B 1个字节 等于 8个二进制位 字节是内存计量的最小单位

数据类型

char 字符型 1字节 short短整形 2字节 int 整形 4字节 long 长整形 4字节 float 单精度 4字节 double 双精度 8字节 系统不会给类新型分配空间,只给类型定义的变量分配空间 sizeof(类型名/变量名)

在linux64位平台 long是8字节

常量与变量

常量是在文字常量区 栈区,堆区,文字常量区,代码区

# 字符常量 字符常量用%c输出
printf("%c",'a')

# 字符变量存的是ASCII值
char ch = 'a'
printf("char = %c", 'a')
# 段整形
printf("short = %hd",10)
# 长整形
printf("long = %ld\n",123);
# 单精度
printf("float = %f\n",3.14f);
# 双精度
printf("double = %lf\n",3.14);

printf("8进制 %#o\n")
printf("10进制 %d\n")
printf("16进制 %#x\n")

# 有符号
printf("%u\n",10U)
printf("%lu",10LU)

char 字符常量 单引号只能作用一个字符

char a = 'A';

数组

数组名是符号常量不允许被赋值

字符数组

定义一个字符数组
未被初始化的空间会补0 
char arr[6] = {'h','e','l','l','o'};
printf("sizeof(arr) = %d\n",sizeof(arr));
%s 遇到0后结束
printf("%s\n",arr)

# 字符数组以字符串的方式初始化 (推荐)
char arr[] = "hello"

char arr[32] = "" // 清空 推荐

# 获取键盘输入 数组名则是首元素地址,不需要加&
scanf("%s",arr)

函数

# %s获取输入时遇到空格回车会结束输入
scanf 

gets # 获取带空格的字符串 (不推荐,gets不会检测空间的有效性,会污染内存) 编译没有错,运行过程中出现的错误(段错误) 操作非法内存。
char buf=[32] = " ";
gets(buf);
printf("%s\n",buf)

fgets   # 从文件中读取字符串
char buf=[32] = "";
fget(buf,sizeof(buf,stdin) # stdin标准输入设备

strlen
sizeof
strlen测量字符串实际长度,遇到\0结束统计
sizeof 测量内从空间的大小

# 输出一个字符串
puts(buf)
fputs(buf,stdout) 

_getch # 不敲回车获取一个字符
getchar() # 需要敲回车回去字符

# rand() 返回随机数,用srand()设置好随机数种子
srand(time(0));
int c = rand();
printf("%d\n", c);

//获取A-Z 对26取余 0 -25
rand()%26+'a'

数组 1、定义数组

int arr[3];

2、获取数组大小和个数

# 数组总元素大小。
sizeof(arr) 

# arr[0]第0个元素代表每个元素的大小
sizeof(arr)/sizeof(arr[0]) 

3、数组
初始化

# 全局数组或变量不初始化,内容为0


# 部分初始化,未初始化部分会被补0
int arr[5] = {10,20,30}

# 全部初始化 可以省略元素个数
int arr[] = {10,20,30}

# 初始化清空数组
int arr[5] = {0}

数组arr作为地址,&arr则代表首地址(&arr[0]的地址),&arr+1则跳过整个数组。 arr与&arr在地址编号上一样,但类型不同。

4、内存和指针 内存地址编号:内存的每一个字节 分配一个号码, 这个号码就是内存地址编号。(唯一) 内存地址编号==地址==指针。 指针:通过指针找到存储空间 完成数据读写。 在32位平台:地址编号大小32位,64则为62位

指针:本质就是地址 内存地址编号。 指针变量:本质是变量,只是该变量存的是地址编号 而不是普通的数据

int num = 30;
// 定义一个指针变量p 存储num的地址  * 修饰p为指针变量,指针变量名称为p,不是*p, 
// int *p中的p必须赋值一个地址,不是地址就报错。
int *p;
p = #

// 使用指针改变num的值 * 修饰p
// 此时*p == num

*p = 10;
printf("%d",num) // 10


&num 是int * 类型, p 也是int * 类型, 因为p存储的是num的地址。
*p == num 都是int类型, 因为*p则是取p所保存的地址编号对应的内容


指针和数组

int arr[5] = {1,2,3,4,5};

printf("%u\n",arr[1]); // arr[1] 展开则是*(arr+1)  [] 是 *() 的缩写(重要)
printf("%u\n",*(arr+1));

数组元素指针

#定义一个指针变量 保存arr数组元素的地址
    int arr[5] = {1,2,3,4,5};
    int *p = arr;   // arr首元素地址
    for (size_t i=0;i<sizeof(arr)/sizeof(arr[1]);i++) {
        //printf("%d\n",*(p+i)) //p[x] = *(p+x)
        printf("%d\n",p[i]);
    }
    
    # 保存第三个元素地址
    int *p1 = &arr[2];
    printf("%d",p1[1]); 
    
    

字符串拷贝

strcpy

# 把src所指向的字符串复制到desc所指向的空间‘\0’也会拷贝过去
char *strcpy(char *dest,cost char *src) 

void strcpy_demo(){
    char dst1[32]="";
    strcpy(dst1,"string\0st"); // str开头函数遇到\0结束
    printf("%s",dst1);
}

void strncpy_demo(){
    char dst2[32]="";
    strncpy(dst2,"string\0sdf3",3); // 拷贝指定数量字符串
    printf("%s",dst2);
}

// 将src拼接到dst末尾
void strcat_demo(){
    char dst[32]="strcat";
    char src[32]="demo";
    strcat(dst,src);
    printf("%s",dst);    
}

void strncat_demo(){
    char dst[32]="strncat";
    char src[32]="demo";
    strncat(dst,src,1);
    printf("%s",dst); // strncatd

}

内存操作函数

// memcpy(void *dest,cost void *src, size_t n)
// 从src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中
// dest 目标内存首地址 src 源内存首地址 dest和src内存地址不可重叠
void memcpy_demo(){
    int num_d[5] = {0};
    int num_s[5] = {10,20,30,40,50};

    memcpy(num_d,num_s,sizeof(num_s));
    for (size_t i =0;i<5;i++){
        printf("%d\n",num_d[i]); // 10 20 30 40 50
    }
}