学习c++的第01天
- 前言
- 1、变量是声明?
- 2.建议定义数据都对其进行初始化
- 3.有符号数和无符号数
- 4.进制间的相互转换
- 5.原反补码
- 6.const 、register 、volatile和typedef关键字
- 7.数据类型的自动转换
- 8.左移<< &右移操作>>
- 9.将data的指定位数进行0、1转化的应用
- 10.循环语句
- while 中的break与continue
- 11.goto跳转语句
- 12.数组
- 总结
前言
日期:2023年6月28日`学习内容:C++数据类型&运算符&原反补码
记录我比较模糊的内容,与其他语言相似的不做记录
1、变量是声明?
- 变量的定义:创建即开辟空间
- 变量的使用;对已存在变量的读写
- 变量的声明 :对变量的类型名称进行声明,但是不为其开辟空间
提前声明关键字:extern
//提前:变量声明 需要加extern修饰 extern int data;
void test03()
{
//先使用
cout<<"data="<<data<<endl;
}
//后定义
int data = 0;
2.建议定义数据都对其进行初始化
字符型初始化’\0’
代码如下(示例):
char ch = '\0';
int num = 0;
float f = 0.0f;
double d = 0.0;
3.有符号数和无符号数
字符型初始化’\0’
代码如下(示例):
//有符号数
int num; //默认省去signed
signed int num ;
//无符号数
unsigned int num;
以一个字节为例:
无符号数范围:
0000 0000 ~ 1111 1111
0 ~ 255
有符号数范围:
1111 1111 ~ 1000 0000 ;0000 0000 ~ 0111 1111
-128 ~ -0 0 ~ 127
因为-0 不好表示所以将其看做-128
所以无符号数的范围为:
-128 ~ 0 ~ 127
4.进制间的相互转换
- 十进制转成二进制、八进制、十六进制全部使用短除法
- 二进制、八进制、十六进制转十进制使用为次幂的方法
- 二进制转成八进制、十六进制
八进制对应3位
十六进制对应4位 - 八进制和十六进制转二进制
- 八进制转十六进制(二进制位中介)
- 十六进制转八进制(二进制位中介)
5.原反补码
- 计算机以补码的形式进行存储
- 负数在计算机以补码的方式存储,非负数在计算机以原码的方式存储
- 补码
原码->反码->补码 - 无符号数和有符号数的正数(都为正数) 原码=反码=补码
- 有符号数的负数
- 反码 = 符号位不变其他位取反
- 补码 = 反码 + 1
-123原码:1111 1011
-123反码:1000 0100
-123补码:1000 0101
- 计算机从存储的补码,取出数据的过程:
- 补码 -> 反码 -> 原码
- 方式一:先取反再加1
- 补码 - >反码 = 符号为不变其他位取反
- 反码 - > 原码 = +1
- 方式二:先减1再取反
- 补码 -1 再取反 得原码
- 补码的意义
-
统一了0的编码
+0补码:0000 0000 -0补码:0000 0000
-
将减法运算变成加法运算
- 假如没有补码 10 - 6
10: 0000 1010 -6: 1000 0110 ------------------- 1001 0000---->-16结果有问题
- 假如有补码 10 - 6
10: 0000 1010 -6: 1111 1010 ------------------- 0000 0100---->4
-
6.const 、register 、volatile和typedef关键字
- const:修饰普通变量
//const修饰data为只读变量 data的本质是变量 //只读变量 只能被初始化 不能被赋值
const int data=100;
data = 10;//err
如果以常量初始化 const修饰的只读变量 那么 只读变量的值 事先存放在“符号常量表中” 不会立即给data 开辟空间,当对data取地址时,系统才会为data开辟空间
const int data=100;
int *p = (int *)&data;
*p = 2000;
cout<<"*p = "<<*p<<endl;//2000
cout<<"data = "<<data<<endl;//100
register:
- register:修饰寄存器变量
如果变量 别高频繁使用 会自动将变量存储在寄存器中 目的:提高访问效率 如果用户想将变量 直接放入寄存器中 可以加register修饰
只是尽量放到寄存器当中
register int data=0;//data将放入寄存器中 //尽量不要对寄存器变量取地址
&data;
//register修饰的变量 只是尽量放入寄存器中
- volatile :强制访问内存
volatile int data=0;//对data的访问 必须冲内存访问
- typedef:给已有的类型重新取别名
不能创建新类型。
将长且复杂的类型名 取一个短小的名称。 typedef作用的步骤:
1、先用 已有的类型 定义一个普通的变量
2、用别名 替换 变量名
3、在整个表达式最前方 加typedef
使用代码示例:
//INT32就是int类型的别名 typedef int INT32;
INT32 data;
int num;//已有的类型任然有效
typedef int MYARRAY[5];
MYARRAY arr;
typedef int *MYP;
MYP p;//int *p; p的类型就是int *类型
7.数据类型的自动转换
- 基本原则就是为了防止数据精度丢失,低精度与高精度运算,会直接转换成高精度
- 有符号的负数与无符号数进行运算时有大坑(会直接将有符号数的1负数位转换成无符号数进行运算) 代码示例如下:
int data1 = -10;
unsigned int data2 = 6;
if(data1+data2>0)
{
cout<<">0"<<endl;//结果输出 }
else
{
cout<<"<=0"<<endl;
}
- int和double参加运算 会将int转成从double类型
- char和short类型 只要参加运算 都会将自己转换成int类型
8.左移<< &右移操作>>
左移操作:
如果:data=0000 0001 如果:data=0000 0001 如果:data=0000 0001 如果:data=0000 0001 ...... 如果:data=0000 0001
data=data<<0; data=0000 0001 == 1==data*2^0
data=data<<1; data=0000 0010 == 2==data*2^1
data=data<<2; data=0000 0100 == 4==data*2^2
data=data<<3; data=0000 1000 == 8==data*2^3
data=data<<6; data=0100 0000 == 64==data*2^6
右移操作:
算术右移、逻辑右移 都是编译器决定,用户无法确定。 无符号数:右边丢弃 左边补0
有符号数:
正数:右边丢弃 左边补0 负数:右边丢弃 左边补0(逻辑右移)
负数:右边丢弃 左边补1(算术右移) 编写代码测试 编译器为那种右移:
如果:data=1000 0000 data=data>>0; data=1000 0000 == 128==data除以2^0
如果:data=1000 0000 data=data>>1; data=0100 0000 == 64==data除以2^1
如果:data=1000 0000 data=data>>2; data=0010 0000 == 32==data除以2^2
如果:data=1000 0000 data=data>>3; data=0001 0000 == 16==data除以2^3
......
如果:data=1000 0000 data=data>>6; data=0000 0010 == 2==data除以2^6
9.将data的指定位数进行0、1转化的应用
案例1:data为1字节 将data的第3,4为清0 其他位保持不变。
data= data & 1110 0111
1110 0111 == ~(0001 1000) == ~(0001 0000 | 0000 1000)
==~(0000 0001<<4 | 0000 0001<<3)
== ~(0x01<<4 | 0x01<<3);
data &= ~(0x01<<4 | 0x01<<3);//推荐
案例2:data为1字节 将data的第5,6为置1 其他位保持不变
data = data | 0110 0000
0110 0000==0100 0000 | 0010 0000==0000 0001<<6 | 0000 0001<<5
== 0x01<<6 | 0x01<<5
data |=(0x01<<6 | 0x01<<5);//推荐
案例3:data为1字节 将data的第3,4位清0, 5,6置1 其他位保持不变
data = data & ~(0x01<<3|0x01<<4) | (0x01<<5|0x01<<6);
10.循环语句
- 常见的基本与Java一样
while 中的break与continue
- break 跳出循环
- continue 直接进入下次循环,在下面的例子中会造成死循环
int i=1;
int sum = 0;
while(i<=100)
{
if(i == 50)
continue;
sum += i;//sum = sum+i;
i++; }
cout<<sum<<endl;//没有结果 while是死循环 反复从i=1 开始
- 循环选择的使用建议
- 知道循环次数,用for
- 只知道循环退出条件,建议用while
11.goto跳转语句
12.数组
- 这里与Java不同的是没有方法是直接来获取数组的长度的
- 一维数组的获取长度
int arr[5] = {0} //推荐这样进行初始化
int length = sizeof(arr)/sizeof(arr[0]) // 获取数组的长度
//sizeof() 是用来获取数的占用字节数
sizeof(arr)/sizeof(arr[0]) //数组占用的总字节数/单个位置所占用的字节
//就是数组的长度
- 二维数组获取长度
int arr[3][4] = {{1,2,3,4},{1,2,3,4},{1,2,3,4}};
int row = sizeof(arr)/sizeof(arr[0]); //获取行
int clo = sizeof(arr[0])/sizeof(arr[0][0]); //获取列
// 数组遍历
for(int i = 0 ;i<row ;i++){
for(int j = 0 ;j<clo ;j++){
cout<<arr[i][j];
}
}
- 一维数组初始化 与 二维数组初始化
初始化推荐如下:
int arr[3] = {0};//{0,0,0}
int arr2[2][3]={0} // {{0,0,0},{0,0,0}}
这下面可以不用看了:
//一维数组
int arr[4] = {1,2,3,4} //全部初始化
int arr[4] = {1,2,3} //部分初始化 {1,2,3,0}
int arr[]={10,20,30,40,50}; //元素个数由初始化个数决定
int arr[4]={0};//将第0个元素初始化为0 其他未被初始化自动补0 推荐
int arr[4]={10};//10 0 0 0
int arr[4]={[2]=10, [3]=30};//指定下标初始化 {0 0 10 30}
//二维数组
//分段初始化 (没有初始化到的默认为0)
int arr[3][4]={ {1,2,3,4}, {5,6,7,8}, {9,10,11,12} }; //完全初始化 只能省略行数
int arr[][4]={ {1,2,3,4}, {5,6,7,8}, {9,10,11,12} };//完全初始化只能省略行数标
int arr[3][4]={ {1,2}, {5,6}, {9,10,11} };//部分初始化 其他值为0
//连续初始化
int arr[3][4]={ 1,2,3,4, 5,6,7,8, 9,10,11,12};//完全初始化
int arr[][4]={1,2,3,4, 5,6,7,8, 9,10,11,12}; //可以省略行数
int arr[3][4]={ 1,2, 5,6, 9,10,11};//部分初始化
案例:
int arr1[3][4]={ {1,2}, {5,6}, {9,10,11} };
int arr2[3][4]={ 1,2, 5,6, 9,10,11};
arr1[1][2] +arr2[1][2] == 11 // arr1[1][2] = 0 ;arr2[1][2] = 11
- 字符数字初始化:使用右边 默认带’\0’
- 其他是字符数组知识点 去看课件吧
总结
这是自学C++第一天 认为需要注意的知识点,目前还是和java很相似的,感觉还没到难点!