/*新手第一次写博客哈,请多多关照
以下其实是我的学习笔记,如有错误敬请指出
配套学习的书籍<<C++从入门到精通(第三版)>> (清华大学出版社)
*/
#include <iostream>//宏定义 -- 头文件引用
#include<iomanip>
#include<stdio.h>//printf输出需要的库
#include<STDARG.H>//使用可变参数函数所需要include的库
/*#define PI 3.1415926 //宏定义常量*/
using namespace std;//命名空间
int func();//笔记函数
void Outputinfo(int num,...);//可变函数的声明
inline int Add(int,int);//内联函数的声明
int* funcTry();//static变量测试函数声明
//--------------------------------------------------------------------------------------
int main()//主函数
{//主函数体
/*cout<<"hello"<<endl;//流输出*/
func();
return 0;//返回值
}
int func()
{ //2.2 常量及符号
/*
-255;//整型常量
//+244 == 244;
//cout<<016<<endl; //以0开头的数据是八进制 所以输出是14
//cout<<0196<<endl; //八进制中出现十进制的9,报错:error: invalid digit "9" in octal constant
//cout<<0xFFFF<<endl;//以0开头的数据是16进制 所以输出是65535
int i = 0xFFFF;
cout<<hex<<i<<endl; //输出十六进制数:ffff
cout<<oct<<i<<endl; //输出八进制数:177777
cout<<dec<<i<<endl; //输出十进制数:65535
cout<<1.2e3; //1200
cout<<sizeof(100L)<<endl;//4
cout<<sizeof(100.0L)<<endl;//12
cout<<sizeof(100u)<<endl;//4 大小不变,但是其可以表达的正数范围增大
cout<<sizeof(100.0f)<<endl;//4 flout标准长度
cout<<sizeof(100.0fl)<<endl;//4 error l,f 在浮点数中没有用,若要使用双精度浮点数则使用double
cout<<"\101"<<endl;//ascii码 A \ddd(三位八进制数)
cout<<"\x0A"<<endl;//ascii码 回车 \xhh(两位16进制数) cout<<PI<<endl;//宏定义常量,在第二行定义,宏常量可以在函数体外的任何地方,一般写在文件开头,不能写在函数体内*/
//2.3 变量
/*
cout<<sizeof(short int)<<endl;//2
cout<<sizeof(int)<<endl;//4
cout<<sizeof(unsigned long int)<<endl;//4
cout<<sizeof(long long)<<endl;//8 长长整形
cout<<sizeof(float)<<endl;//4 浮点数又称实型
cout<<sizeof(double)<<endl;//8 双精度
cout<<sizeof(long double)<<endl;//12 长双精度
cout<<sizeof(char)<<endl;//1一个字节
cout<<char('A'+32)<<endl;//a 如果没有强转成字符则输出是97 字符变量的算术运算
cout<<('A'-'a')<<endl;//-32 两个字符之间也是可以计算的
for(int i = int('A');i<=int('A')+32;i++)cout<<char(i)<<' ';//A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a 从A到a的32个字符.*/
//2.4 常用数据类型
/*
基本类型:短整型;整形;长整型(浮点型不算是基本类型吗?)
构造数据类型:布尔型;@枚举类型;数组类型;结构体类型;@公用体类型;类类型
指针类型 [引用类型和指针类型不是同一类,而只是具有类似的处理逻辑]
引用类型
@空类型
实类型:浮点型数据是有有效位数限制的
float i = 1.234567890;
cout<<i<<endl;//1.23457 -- cout输出限制六位有效数字 注意:不是小数点后六位
float i = 0.0000000000001;
if(i==0.0)cout<<"true";
else cout<<"false";//当对i的精度要求非常高时,这段代码可能发生未知错误(暂时无法尝试出错误情况),另外注意float 0 与int 0不是一个东西,不要混用
char c = 97;//等效于 char c = 'a';*/
//2.5 数据的输入输出
/*
C++中将数据之间的传输称作流,分为输出流与输入流,意义:将程序与具体的硬件io分割,保证灵活性与可用性
标准IO操作中cin只是指键盘输入,cout是输出到屏幕 若cin>>x输入了一个str则x需要为char[]或者有指向位置的char*[若char*没有预先指定位置,则会输入错误]会直接出现runtime error应用程序会直接崩溃,编译器只是会发出警报而不会阻止编译
char*p;
cin>>p;//warning: 'p' is used uninitialized in this function [-Wuninitialized]
cout<<p;
io操作中的函数:(需要include<iomanip>)
1. long setf(long f)??? 按照f对应的枚举变量值设置输出格式,并返回之前设置的输出格式(可以使用多个枚举操作符作为传入参数,两个参数之间用按位或链接)--没有理解
2. long unsetf(long f)??? 根据参数f格式化之前的设置--没有理解
3. int width(int w)??? 设置下一个输出值的域宽,返回上一个输出值的域宽--没有理解
4. int width()??? 3号函数的重载,返回当前设置的域宽,若未设置则返回0--没有理解
[5.]setiosflags(long f) 与setf(long f)等效,返回一个输出流[即可以像字符一样连缀输出]
[6.]resetiosflags(long f) 与unsetf(long f)等效,返回输出流
7. setfill(int c) 设置ASCII码为c的字符为填充字符
8. setprecision(int n) float输出精度为n
9. setw(int w) 设置下一个数据的域宽
(所有打问号的方法都是作为cout的属性进行修改e.g.cout.width(10))
**用于存放输出数据的宽度称为“域宽”。如果域宽小于被打印数据的宽度,数据通常会在域内右对齐。如果输出值的宽度大于域宽时,域宽是自动增长的。
cout<<setw(8)<<setfill('*')<<10<<endl;// ******10
cout<<setprecision(2)<<123.456<<endl;//1.2e+002
cout<<setiosflags(ios::fixed)<<123.4567890101112<<endl;//123.456789九位有效数字
cout<<setiosflags(ios::scientific)<<123.4567890101112<<endl;//123.457
cout<<setiosflags(ios::scientific)<<23.4567890101112<<endl;//23.4568六位有效数字
cout<<setiosflags(ios::uppercase)<<hex<<123456<<endl;//1E240 针对数值16位输出,使用大写字母(如果是字符串输出则无效)
不用调用成员函数的控制对象:
dec oct hex ws endl
十进制 八进制 十六进制 输出流中读取空白字符串 输出换行符并刷新字符串
ends flush
输出空字符\0 只刷新一个输出流
setiosflags选项:
fixed scientific left right skipws uppercase
以定点数方式展示 科学计数法显示 左对齐 右对齐 忽略前导空格 大写字母展示16位
lowercase showpos showpoint
小写字母展示 正数显示正号 强制展示小数点和无效的0
printf输出:
printf("[控制格式]...[控制格式]...",数值列表) 控制格式由%与特定字符表示
控制格式:%[占位符][域宽][长度]输出类型
域宽:输出的最小长度,若实际要输出的长度大于域宽则增加域宽直到适应
占位符:若没有域宽长则用占位符占位
长度:表示输出的最大长度
输出类型:d o x u c s f e g
依次是:十进制有符号,八进制,十六进制,十进制无符号,单字,字串,小数形式,科学计数法,以小数与科学计数法中短的方法输出
printf("% 4d\n",1);// 1
************详细资料还是在书上,相关命令太多,记不下来***************************************
*/
//3.1 运算符
/*
c++新增的运算符有: ::(域运算符); ->(成员指针运算符)
单目运算符:仅操作一个数 双目运算符: 操作其左右的两个数
算数操作符...
关系操作符:大于小于等
逻辑运算符: &&(双目) ||(双目) !(前置单目)
赋值运算符: =;+=;-=;*=;/=;%=;
<<=(左移赋值);>>=(右移赋值);&=(按位与);|=(按位或);^=(按位异或)
位运算符:&;|;^;~(取反)[前三个操作符优先级依次降低]
按位与:两个二进制对象从低位到高位对齐,高位补零,每一位进行与运算(不是代数加法,不存在进位){
1&1=1
1&0=0
0&0=0
}
按位或:两个二进制对象从低位到高位对齐,高位补零,每一位进行或运算{
1|1=1
1|0=0
0|0=0
}
按位异或:{
1^1=0
1^0=1
0^1=1
0^0=0
}
取反:{1->0;0->1}
移位运算符:<<;>> 溢出位丢弃,空位补零,左移相当于2^n,右移相当于除以2并丢弃小数
sizeof运算符...
条件运算符:[c++中仅有的一个三目运算符]
<表达式1>?<表达式2>:<表达式3> {若表达式1的值为true则返回表达式2的值}
int x = true?(int y = 10):(int y = 11);//expected primary-expression before 'int';expected ')' before 'int;expected ':' before ';' token;expected primary-expression before ';' token;'y' was not declared in this scope
//简而言之,禁止在条件运算符中声明变量,但是可以赋值变量
逗号运算符:将多个表达式组成一个表达式
for(int i = 0;i<10;cout<<i<<' ',i++);//0 1 2 3 4 5 6 7 8 9*/
//3.2 结合性和优先级
/*
返回值为某个单独变量的时候,优先级较高
左移右移运算符比算术运算等级低但是比关系操作等级高
按位与,按位或,按位异或低于关系操作但高于逻辑与或非操作*/
//3.3 表达式
/*
对于逻辑与运算,若第一个操作数为假,则不再进行第二个操作数判断
对于逻辑操作或运算,若第一个操作数为真,则不再进行第二个操作数判断
逗号表达式:e.g.{表达式1,表达式2}先求解表达式1,再求解表达式2,并将表达式2的值作为整个逗号表达式的值.类似的,当有多个表达式时,以最后一个表达式的值与类型作为整个表达式的返回值
逗号表达式可以嵌套: 表达式1,(表达式2,表达式3)
int i,n,m;
cout<<(i = 10,n=11,m=12)<<endl;//12
int i,n,m;
cout<<(i = 10,n=11,i+n)<<endl;//21
表达式中的类型转换分为 1.隐式转换(发生在不同数据类型变量混合运算中,由编译器自动转换)
2.强制转换(通过手动调用类型转换运算实现)
int i = float(1.93456);
cout<<i<<endl;//1 不是四舍五入,而是丢弃小数点
float m = double(5.555555555555555555555555555555555);
cout<<setprecision(6)<<m;//5.5555553436279296875只有七位准确数字 如果precision是6 5.55556 不是转换时的四舍五入而是输出时四舍五入
double m;
m = float(4.444444)+double(5.555555555555);
cout<<setprecision(20)<<double(5.555555555555)<<endl;//5.555555 55555500 02467 double14位
cout<<setprecision(20)<<float(4.444444)<<endl; //4.444444 17953491 21094float七位有效
cout<<setprecision(20)<<m<<endl; //9.999999 73508991 14679 相加13位准确
//不存在四舍五入现象
整形数据计算向int和long靠拢,有必要时转向long:
(unsigned long)<-long<-unsigned int<-int<-[short,char]
浮点型变量向double靠拢:
double<-float {所有浮点型运算均是使用double进行运算,即使只有float}
强制转换有两种表达形式:
int(variable_name)
(int)variable_name
强制转换的意义,如当遇到int=float+float时不使用强转int则:(float->double)*2+double->int会比使用强转多一次转换.另外有时编译器没有自动转换的地方使用强转可以避免程序错误
*/
//3.4 语句
/*
特殊的语句:
1.空语句:e.g.while(true) ; 只有一个空语句没有内容作为占位内容
2.复合语句:e.g.{
x = 1;
y = 2;
a = x+y;
}若干条语句组成的整体,大括号后面不打分号,在所有能使用简单句的地方都可以使用复合句.
复合句相当于一个没有返回值的简单句,不能做右值,想要将数值传出去只能用上级scope的变量承接
int i=1;
if(i==1){int m = 1;}
else{int n = 2}
cout<<m<<n<<endl;//error: 'm' was not declared in this scope error: 'n' was not declared in this scope 条件句中声明变量在scope外也无法访问*/
//3.5 判断左值和右值
/*
每一个表达式的结果都可以被分成左值与右值,左值与右值的分类在于其是存在于等号左边还是右边,左值是在主存中持续存储的数据,右值是暂时存储的数据
左值都可以出现在左侧,但也可以出现在右侧客串右值
对于有const修饰的左值,属于特殊情况*/
//第四章:条件判断语句
/*
if;
if-else;
if-else if-else...;
(ex1)?ex2:ex3;{注意这是一条语句}
(ex1)?((ex_a)?ex_b:ex_c):ex3
switch(input_variable){
case variable_case_1:
...
break;//注意不能缺少break
....
default://default可以不写,若不写则没有对应操作
....
}*/
//第五章:循环语句
/*
while(bool_exp){statements} 表达式不为空,否则报错;非零为true,0为false
do{statements}while(bool_exp); statements至少执行一次,循环语句之后必须有分号
for循环的表达式省略:for(ex1;ex2;ex3){statements}
ex1省略:变量需要在scope外声明
ex2省略:循环无终止条件,变为无限循环
ex3省略:变为while类似,在scope中增加跳出语句{注意:for loop中无ex3则continue直接跳转到ex2处执行判断}
for(int i = 0;;i++){
if(i>=10){cout<<i;return 0;}
}
cout<<"loop end"<<endl;//10 成功进入循环,所以无ex2时默认为true
goto语句:
int i = 1;
label://label名称不是固定的,只要是满足该语法均可g.e.label1
cout<<i++<<' ';
if(i<=10)goto label;
cout<<i<<endl;//1 2 3 4 5 6 7 8 9 10 11
goto语句不可以用于跳过非复合语句的其他代码:
goto label1;
int i = 1;
label1://会报错,因为不能直接跳过非复合语句
.......
应该写成:
goto label1;
{
int i = 1;
}
label1://这样就行了
.......
*/
//第六章:函数 6.1~6.6
/*
定义函数时的形参,在未出现函数调用时不会占用内存空间
一般类型以及指针变量都有实参值传入到形参中的过程(pointer是将实参中的内存地址复制到形参)
若使用引用变量作为形参,则没有值传递的过程
默认参数必须存在于非默认参数右侧
可变参数://需要include <STDARG.H>
e.g.printf原型函数:
_CRTIMP int_cdecl printf(const char *,...);
void Outputinfo(int num,...)
Outputinfo(2,"hello1",3,"hello2",4,"hello3");//hello1 3 hello2 4 取出符合函数中取出顺序的变量
stdarg.h 头文件定义了一个变量类型 va_list 和三个宏,这三个宏可用于在参数个数未知(即参数个数可变)时获取函数中的参数.可变参数的函数通在参数列表的末尾是使用省略号(,...)定义的。
va_list:这是一个适用于 va_start()、va_arg() 和 va_end() 这三个宏存储信息的类型。
void va_start(va_list ap, last_arg):这个宏初始化 ap 变量,它与 va_arg 和 va_end 宏是一起使用的。last_arg 是最后一个传递给函数的已知的固定参数,即省略号之前的参数。
type va_arg(va_list ap, type):这个宏检索函数参数列表中类型为 type 的下一个参数。
void va_end(va_list ap):这个宏允许使用了 va_start 宏的带有可变参数的函数返回。如果在从函数返回之前没有调用 va_end,则结果为未定义。
Outputinfo(3,"hello1",3,"hello2",4,"hello3");//hello1 3 hello2 4 hello3 6946688 前面的2或3是用来标记后面输入的变量的数量
所有的函数需要创建在函数体外
内联函数:编译器会自动在调用内联函数的地方创建一个函数的副本(即是增加主程序)而不是通过跳转调用进行引用[意义:对于较短的函数可以省去跳转以及声明产生的开销,多用于应用优化]
cout<<Add(1,2);//3
*/
//6.7 变量的储存类型
/*
四种变量储存类型:
1.auto变量 :默认的储存类型,所有没有特别说明的变量均是auto变量[所有我们使用的非全局变量: (auto) int x = 10;]
auto特性:作用域存在于对应的scope中;
动态存储,自动释放,以栈的方式进行存储[因为scope是栈结构的];
在不同的scope中使用相同名称的auto变量不会引起错误;
2.static变量
:在变量前面加上static修饰可以将变量修改为静态变量[e.g.static int x = 10;]
(1).若在某个函数中创建static变量,则在整个工程中所有调用该函数地方均使用该变量,且只有第一次定义的时候进行初始化,后面运行该变量均保持其原有值
(2).若在某个文件中以全局方式进行定义,则作用域是该文件内
总结:static作用域与auto相同,但是作为函数体中定义的变量时可以做到不同调用间数据遗传.static变量存在的时间是整个工程中,如果将其地址传到global中或者其他函数中可以类似全局变量使用.
int*p = NULL;
for(int i = 0;i<3;i++){
p = funcTry();
cout<<"pointer output"<<p<<' '<<*p<<endl;
}
0 0x47700c
1 0x47700c
2 0x47700c
pointer output0x47700c 3
3 0x47700c
4 0x47700c
5 0x47700c
pointer output0x47700c 6
6 0x47700c
7 0x47700c
8 0x47700c
pointer output0x47700c 9
3.register变量 :手动要求编译器将反复使用的变量放在寄存器中,减少读取RAM耗费的时间.但是在实际编程中使用不多,因为编译器会自动选择变量放到寄存器中,并且若寄存器没有足够空间或者输入的类型不支持存入寄存器则编译器会自动忽略命令,相当于命令无效.[具体使用时只有动态存储类型可以放到寄存器中,一般是程序优化时使用该语句]
4.extern变量
:用于声明全局变量,将某一个文件中的全局变量变为main文件中定义的全局变量的引用
e.g.
main.cpp:
int i = 0;//定义全局变量
int main(){
func();
.....
return 0;
}
functions.cpp:
extern int i;//声明这里的全局变量使用main.cpp中定义的那个
void func(){
................
}
*/
return 0;
}
//---------------------------------------------------------------------------------------------
void Outputinfo(int num,...){
va_list arguments;
va_start(arguments,num);//初始化arguments,以num为基准确定后面的省略参数位置
while(num--){//读取的次数
char*pchData = va_arg(arguments,char*);//返回符合参数要求的下一个参数
int iData = va_arg(arguments,int);
cout<<pchData<<' '<<iData<<'\t';
}
va_end(arguments);//终止可变参数的使用方便函数return
}
inline int Add(int x,int y){//这里的inline可以不写,只要声明写了就行
return x+y;
}
int* funcTry(){
static int x = 0;//必须初始化,否则后面无法调用只能够覆盖,于是就没有数据遗传的意义了
int tmp = x+3;
for(;x<tmp;x++){
cout<<x<<' '<<&x<<endl;
}
return &x;
}
菜鸟 C++ learning 1
最新推荐文章于 2023-10-25 21:34:46 发布