C语言常用知识总结

数据类型

一字节等于八位, char占一字节,2^8 = 256,所以char可以存256个数字
以此类推有
数据类型及范围
在这里插入图片描述
usigneded类型的
在这里插入图片描述
注:int16_t 是16位两个字节
当比较两个小数是否相等时,不能直接a==b 应该取a-b<= 0.0000000001才对

进制转换

计算机由2进制进行存储,十进制、八进制、十六进制需要转化为2进制,方法如下:
例:比如10进制 25 转化为除2 商 余数
25 / 2 = 12 12 余1
12 /2 = 6 6 余 0
6/2 = 3 3 余0
3/ 2 = 1 1 余1
1/ 2 = 0 0 余1
当商为0时,余数自底向上就是其转化结果11001;转为16进制除16,8进制除8以此类推。
1位 16进制 相当于 2进制 4位
2进制 的3位相当于8进制1位

原码、反码、补码

计算机内存 都是补码
正数 原码就是补码
负数
原码 --> 反码 原码 符号位不变, 其他位 按位取反 得到反码
反码 --> 补码 补码= 反码 + 1

比如 -25 原码 25 --> 0001 1001 -25的原码 1001 1001 -25 的反码 1110 0110 -25的补码 11100111
按位取反 -i 取负 !i 取非

大小端

大端存储 : 交换机 网络字节序 低地址存高字节
小端存储 : window 操作系统 低地址存低字节
字节序颠倒
小端存储 0000 0000 0101 0011 --> 大端存储 0101 0011 0000 0000
写一个判断大小端的函数 返回值1 的时候 就是一个小端存储

unsigned fun()
{
int i= 1;
return *(char*)&i;
}  // 返回值1 的时候 就是一个小端存储 

注:unsigned --> unsigned int int 是默认缺省类型

类型转换

1 int a ; char c =a; --> char c = (char ) a; 强制类型转换
2 显式 和隐式的类型转换
显式类型转换有四种
static_cast
dynamic_cast
const_cast
reinterpret_cast
static_cast<类型> ( 变量) ; 静态类型转换 与强制类型转换一样, 不能保证安全
dynamic_cast<类型>(变量); 动态类型转换 , 一般是使用在父类和子类之间的
父类指针指向子类对象 CFather * pF = new CSon; CFather 是CSon CSon1 , CSon2的父类
父类指针指向的子类对象的类型 是不是你要转换的类型 是的话 , 调用成员没问题, 不是会崩溃
可以类型转换 将pF的类型转换为 CSon
(CSon*) pF 或者 static_cast<CSon*>(pF) ;
为了避免上面的问题, dynamic_cast 多了一个校验机制, 父类子类类型转换时,
父类指针指向的(子类对象)的类型 是你要转换的类型 , 我们可以得到非空的地址 , 如果不是 , 得到的是一个空 NULL 地址

CFather * pF = new CSon;
CSon *s = dynamic_cast<CSon*>(pF) ;   // CSon与CSon*  一致  

所以s 就是非空的 ,

CSon1 *s = dynamic_cast<CSon1*>(pF) ;

s就是空的

CSon1 *s = static_cast<CSon1*>(pF) ;

s是非空的

CSon1 *s = (CSon1*)pF ;  

s也是非空的
if( s ) s->fun(); --> 用dynamic_cast 不会崩溃
const_cast<类型>() ; 去常转换 去掉const修饰
常对象只能调用常函数
void fun( const AA & a){
a.常函数(); -->想让他能够调用一般函数 就可以使用 const_cast(a) .一般函数
}
reinterpret_cast 万能转换 重解释类型转换 整型和类之间不能转换 但是使用 reinterpret_cast 可以转换 , 转换之后, 是否安全不考虑
一般用来, 编译 会有语法问题 类型不过 , 可以使用reinterpret_cast 通过编译

隐式类型转换
int a = -5 ; unsigned int b = 2;
if(a + b > 1) 真 else 假 ;
a + b > 1 实际是计算机补码 执行 -5的补码特别大 == > (unsigned int ) a a+b --> (unsigned int ) a + b
结果 会特别大 > 1 结果就是真
char b[100]= {};
int a = -5;
if( a + sizeof(b) > 1 ) --> sizeof 类型 是无符号的 unsigned int 和上面类似
std::vector::sizetype 无符号的

隐式类型转换 如何运算: 对于 int a char b a = b; --> a= (int)b

  1. 赋值操作 , a, b 的类型不会发生变化 , 应该是表达式的返回值类型发生变化
  2. 如果b是一个小类型 a是大类型, 转换的过程 , 要保证值不变
  3. 如果b是一个大类型, a是小类型, 转换就会发生截断 (1. 可以使用2进制截断 2. 采用补偿的方式 )
    char a int b a = b ; a = (char ) b b的结果就取 低字节一个字节从32位取低8位
    b = 300 a = (char) 300 ; a = 300 - 256 127 + 1 --> -128 127 + 1 - 256 --> -128

a的范围 -128 - 127 +或- a的表示个数的整数倍 , 让他的值在取值范围内 300 +/- 256* k --> 在-128 到127 之间

(5) scanf printf
scanf ("%d" , &a); 地址传递 &a %s 遇到空格就结束了 Hello World --> Hello
gets(缓冲区) 可以完成 Hello World
printf %d %p %u %f %lf %ld
补位 %02d 2位长 补0

位运算

<< 左移一定补0
>> 右移 除了符号位 要看类型
无符号的类型 , 一定补0 有符号类型 才会根据 符号位 符号位为1补1,符号位为零,补0 。
~ 按位取反 ^ 异或 相异为1 相同为0 看crc校验 crc-8 crc-16 模2除法 --> 异或
& 一般用来位置0 | 一般是位置1

运算符优先级

运算符优先级
结合方向 单目 三目 赋值 是自右向左的 其他都是左到右
int (*p)[10]; --> () 最高 p 是一整体 他就是指针 --> 数组指针
int
p[10]; p[] --> 结合 p[] 数组 是单目 []是前导 p[] 先 所以是数组 -->指针数组
( ( CDlg
) theApp . m_pKernel ) -> fun(); .是前导 (type ) 是单目 theApp . m_pKernel 外面不用加括号

&& || 短路语句 和优先级是什么关系 ?
优先级是用来分析, 代码执行流程, 说白了是运行时, 短路语句是编译时的 , 要不要去执行
a = b = c = 1;
a++ || b++ && c++ ; 表达式结果 --> 真
b c 的值? 短路语句 , 上帝的右手 凌驾在优先级之上的规则 短路语句 --> b++ c++ 不执行的

你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。

流程结构

顺序就是自上而下执行。( goto loop )
选择 单选多选 switch if

switch( 整型变量或表达式 )
{
    case  整型的常量或表达式:
    case 1: case 3:  case 5: case 7;
    day = 31;
    break;
    default: break; //遇到break;退出, 不然是自上而下依次执行
}

if( a )
if(b)
c = d ;
else
d= f;
else 和哪个if 结合 :跟最近的相结合

循环 一般是给一段儿循环的代码,让你看他是什么含义。 while 和 do{} while 的区别 死循环的考察

宏定义和预处理

#define F(x) xx 这种写法不安全。 应该写为 #define F(x) ((x)(x))
F( 2 + 5 ) --> 2+5 * 2 +5 而不是 想要的 (2+5 ) * (2+5)
宏定义只是单纯的替换,我们在处理的时候先去替换。改过来之后再分析题目。
宏可以定义常量。const 也可以。他们有什么区别?

#操作都是预处理。是编译之前完成的工作。
#ifdef UNICODE
#define MessageBox MessageBoxW
#else
#define MessageBox MessageBoxA
#endif // !UNICODE

NULL 空指针 int* p = NULL; 在c中 int *p = 0; c是不可以的 如果是C++ int p = 0 ; 没有问题的.
/
Define NULL pointer value */
#ifndef NULL
#ifdef __cplusplus //定义c++的宏
#define NULL 0
#else //就是c
#define NULL ((void *)0) //也就是说 c里面NULL是带类型的
#endif
#endif

nullptr; 关键字 专门用来做空指针的 C++的
#define DEBUG 1
#if DEBUG
//执行代码

#endif// 可以通过控制 DEBUG 是1还是0 还选择是否执行这段代码
宏定义还可以去取消 #undef AAA 取消AAA的宏
防止头文件重复包含
#ifndef _A_H
#define _A_H

#endif//_A_H
不这样 , 就会多次定义 --> 重定义 编译不过
#pragma once
宏定义里面的 # 和 ##
#的作用是将#后面的转换成字符串。
#define str(s) #s
printf ( str(m) );
##的作用 将前后两端拼接在一起。
#define Root “C:/colin/”
#define Path(a,b ) a##b
printf( Path(Ro , ot) ) --> printf ( Root ) --> printf( “C:/colin/”);
char * a = “hello”; printf (a);

数组 二维数组 和指针

数组的定义。相同数据类型的元素存储的连续的空间里。这样的存储结构就是数组。
int a[4]; 行优先存储。 int * p = a; a和p 等价
用法:
1)a 数组名。首元素地址, sizeof(a) 返回数组所占空间的大小。也就是元素所占空间大小 * 元素个数。
2)a 常量 a++ 是非法 a是首元素的地址。 首元素 a[0] a的类型是 int* a是0x10 , a+1?
指针的偏移 按照单位去偏移 a+1 是a 向右移动一个单位 , 是多少 + 1 * sizeof( 指向的类型 ) = 0x 10 + 4 = 0x14

  1. &a 怎么理解 ? a的类型是 int* &a 是整个数组的地址 &a的类型是 int()[4];
    如果a 是0x10 的话 , &a + 1 是多少? &a + 1 相当于 &a 向右移动一个单位 , 1个单位是4个整型 &a 也是0x10 ,
    所以 &a + 1 是 0x 10 + 4
    sizeof(int) = 0x20
    指针的加减法 --> 指针的偏移

二维数组 是一维数组的扩展,可以理解二维数组是每一个元素都是一个数组的数组。
int a[3][10]; 我们可以理解。a[0] a[1] a[2] 每个元素都是一个int[10]的数组。
int (p ) [10] = a ; p +1 是在p的基础上移动一个单位 , 移动 10个int 因为int()[10]
int *pp = (int * ) a;
用法:

  1. a[3][10] &a 代表整个数组的地址, 他类型是指向整个数组 &a 的类型 就是 int ()[3][10] a是0x10 --> &a 也是0x10
    &a +1 是多少? &a 的类型 就是 int (
    )[3][10] &a+1 是在a的基础上 移动 3*10个int 也就是 0x10 + 30 *4 = 0x10 +120 --> 0x88
  2. a的数组名 , 代表首元素的地址。首元素是一个数组 a的类型就是 数组指针 --> a的类型是 int(*)[10]
    a是0x10 求a+1 是多少 ? a+1 是a的基础上移动 一个单位 1个单位是10个元素的数组 , 所以移动 10个int 0x10 + 10 *4 = 0x38
  3. a等价于 &a[0] 也就是 &a[0] 类型也是 int(*)[10] … 求 &a[0] + 1 与上面a+1相同
  4. a[0] 是第一个元素的名字, 也就是数组名, 也就是首元素地址 , 也就是 &a[0][0] 那么 a[0]的类型是 int*

如何看出类型 可以用关键字:auto

宏和指针

#define WORD char* 宏定义,不要轻易在结尾加;
WORD pstr , pp ; sizeof(pstr) ,sizeof(pp) ;
宏定义先去简单的去替换。
char * pstr , pp; pstr char* pp char --> 结果是4,1 (32位)

  1. 函数 和指针 函数 考点 就是 值传递 地址传递
void func ( int arr[10] , int nlen)   arr-->  int *     --> void func ( int * arr , int nlen) 
{
     sizeof( arr ) ;  // 得到的?  -->sizeof( int * ) 找不到结尾
}
void func ( char* szstr ); // 字符串\0结束 可以找到结尾 
void   func ( int a[3][10] , int col , int row )    a 是什么类型?   int a[3][10]   -->  int (*a) [10] --> void   func ( int  (*a)[10] , int col , int row ) 
{
     sizeof( a ); // ?   a是个指针    32位 就是4
}
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SS_zico

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值