C2变量及简单数据类型
C2.5字面量
2.5.1整数
#include<iostream>
#include<stdio.h>
using namespace std;
int main(){
//字面量
printf("17: %x, %d, %o\n",17,17,17);
cout << "17: " << hex << 17 <<", " << dec << 17 << ", " << oct << 17 << endl;
//整数字面量(interal literal)
int b1 = 512;
cout << "b1 = "<< dec << b1 << endl;//dec此处不可忽略,因为前面的oct把cout的环境配置成了八进制,这里要改过来
return 0;
}
输出
17: 11, 17, 21
17: 11, 17, 21
b1 = 512
2.5.2字符及字符串
#include<iostream>
#include<stdio.h>
using namespace std;
int main(){
//字面量
printf("17: %x, %d, %o\n",17,17,17);
cout << "17: " << hex << 17 <<", " << dec << 17 << ", " << oct << 17 << endl;
//字符及字符串
char c2 = '\\';
cout << "c2 = " << c2 << endl;
cout << "I've told you, \"C/C++ is hard to learn.\"" << endl;
cout << "Popular languages:\n\tJavaScript\n\tPython\n\tJava\n\tC++" << endl;
string s2 = R"(I've told you, "C/C++ is hard to learn.")";
cout << s2 << endl;
return 0;
}
输出
17: 11, 17, 21
17: 11, 17, 21
c2 = \
I've told you, "C/C++ is hard to learn."
Popular languages:
JavaScript
Python
Java
C++
I've told you, "C/C++ is hard to learn."
2.5.3浮点数
#include<iostream>
#include<stdio.h>
using namespace std;
int main(){
//字面量
printf("17: %x, %d, %o\n",17,17,17);
cout << "17: " << hex << 17 <<", " << dec << 17 << ", " << oct << 17 << endl;
//浮点数字面量
auto a3 = 3;//auto编译器自动推断类型int
auto b3 {3.0};//默认双精度
auto c3 {1.2E-5};//double
auto d3 = 1.2E+5L;//long double
auto e3 = -3.01e+12f;//float
cout << "Name:\ta3\tb3\tc3\td3\te3\n";
cout << "Type:\t " << typeid(a3).name() << "\t" << typeid(b3).name()
<< "\t" << typeid(c3).name() << "\t" << typeid(d3).name()
<< "\t" << typeid(e3).name();
float f5 = 3.1f;
double g5 = 3.1;
return 0;
}
输出
17: 11, 17, 21
17: 11, 17, 21
Name: a3 b3 c3 d3 e3
Type: i d d e f
C3语法基础
C3.1源代码格式
C3.2源代码符号
C3.3操作符(Assignment)
C3.3.1复合
C3.3.2求模表达式
#include<iostream>
using namespace std;
int main(){
//求模操作符
int a = 10;
int b = 10 % 7;
printf("%d is an %s number.",b,b%2 == 0?"even":"odd");
//b%2 == 0?"even":"odd"条件表达式 如果True表达冒号之前,False表达冒号之后
return 0;
}
输出
3 is an odd number.
#include<iostream>
using namespace std;
int main(){
int age = 63;
int retired = (age >= 60? 1:0);
cout << "retired = " << retired << endl;
return 0;
}
输出
retired = 1
C3.3.3比较与逻辑
#include<iostream>
using namespace std;
int main(){
//比较与逻辑
int a = 10;
cout << "a > 5 : " << (a>5) << endl;
cout << "a < 20 and a >= 10 : " << (a < 20 && a >= 10) << endl;
cout << "a == 9 : " << (a == 9) << endl;
cout << "a != 3 : " << (a != 3) << endl;
cout << "a > 100 or a < 20 : " << (a > 100 || a < 20) << endl;
cout << "not a >= 10 : " << (!(a >= 10)) << endl;
return 0;
}
输出
a > 5 : 1
a < 20 and a >= 10 : 1
a == 9 : 0
a != 3 : 1
a > 100 or a < 20 : 1
not a >= 10 : 0
C3.3.4赋值操作符
C3.3.5递增与递减
#include<iostream>
using namespace std;
int main(){
//递增与递减
int a = 0;
a ++;//++递增操作符,①a = 1,②a ++ 作为一个表达式,返回a递增之前的值
//先取值后递增
++ a;//①a = 2,②++ a作为一个表达式,返回a递增之后的值
//先递增后取值
int i = 10,b,c;//b,c未作初始化,不知道是多少
b = i ++;
c = ++ i;
cout <<"i = " << i << ",b = " << b << ",c = " << c << endl;
return 0;
}
输出
i = 12,b = 10,c = 12
#include<iostream>
using namespace std;
int main(){
//递增与递减
float f = 10.1f,g,h;//注意10.1f , 10.1默认double
g = f --;
h = -- f;
cout << "f = " << f << ", g = " << g << ", h = " << h << endl;
return 0;
}
输出
f = 8.1, g = 10.1, h = 8.1
C3.5隐式类型转换
在以下三种情况,C/C++会进行隐式类型转换(implicit type cast):
- 变量初始化或者赋值时,值与变量的类型不同;
- 表达式中不同类型的变量、值进行运算时;
- 函数参数传递时;
· 将存储范围和精度较低的对象赋值给存储范围更大、精度更高的对象是安全的,反之则不然。
· 当表达式中两种不同类型的对象进行算术运算时,编译器总是将较小类型转换为较大类型再进行计算。
#include<iostream>
using namespace std;
int main(){
//以下除标明以外均是错误的,要避免!
bool a = 3.0;//double ---> bool
float b = -9999.2301; // double ---> float
int c = b;//float ---> int
unsigned int d = c;//int --->unsigned int 无符号
short e = d; // unsigned int --->short 有符号
double f = b; //可以,float --->double
cout << "a = " << a << ", b = " << b << ", c = " << c << ", d = " << d <<
", e = " << e << ", f = " << f << endl;
return 0;
}
输出
a = 1, b = -9999.23, c = -9999, d = 4294957297, e = -9999, f = -9999.23
- 列表初始化可以帮忙检查是否含有不允许的隐式类型转换
#include<iostream>
using namespace std;
int main(){
char c {712};//char:-127-128
unsigned int f{-1};
return 0;
}
输出
grammer.cpp: In function 'int main()':
grammer.cpp:5:16: error: narrowing conversion of '712' from 'int' to 'char' inside { } [-Wnarrowing]
char c {712};//char:-127-128
^
grammer.cpp:6:22: error: narrowing conversion of '-1' from 'int' to 'unsigned int' inside { } [-Wnarrowing]
unsigned int f{-1};
^
#include<iostream>
using namespace std;
int main(){
//凡事绕着走
int i = 3;
auto j = 10 / i; // 整数/整数 = 整数
auto k = double(10.0) / i; // 不同类型的运算,要先转化为精度更高的那一种类型,再进行计算
auto z = i/double(10.0);
auto a = (unsigned int)10/i;//无符号整数/整数 = 无符号整数
auto b = double(10.0)/3.0f;
cout << "10/3 = " << j << ", type = " << typeid(j).name() << endl;
cout << "10.0/3 = " << k << ", type = " << typeid(k).name() << endl;
cout << "3/10.0 = " << z << ", type = " << typeid(z).name() << endl;
cout << "(unsigned int)10/3 = " << a << ", type = " << typeid(a).name() << endl;
cout << "10.0/3.0f = " << b << ", type = " << typeid(b).name() << endl;
return 0;
}
输出
10/3 = 3, type = i
10.0/3 = 3.33333, type = d
3/10.0 = 0.3, type = d
(unsigned int)10/3 = 3, type = j
10.0/3.0f = 3.33333, type = d
3.6显式类型转换
#include<iostream>
using namespace std;
int main(){
char c = 'k';
cout <<"c = " << c << endl;
cout << "ASCII code for 'k': " << int(c) << endl;
cout << "ASCII code for 'k': " << (int)c << endl;
cout << "ASCII code for 'k': " << static_cast<int>(c) << endl;
return 0;
}
C3.7使用函数
#include<iostream>
#include<math.h>
#include <stdlib.h>
using namespace std;
int main(){
double x = 2,y = 8;
cout << "2^8 = " << pow(x,y) << endl;
cout << "round(25.51) = " << round(25.51) << endl;
cout << "floor(25.997) = " << floor(25.997) <<endl;
cout << "ceil(25.01) = " << ceil(25.01) << endl;
cout << "sqrt(9) = " << sqrt(9) <<endl;
int r0 = rand(); //0~RAND_MAX之间的随机数
int r1 = rand() % 100; //0~99之间的随机数
double r2 = 0.1 + 0.1 * rand() / RAND_MAX; //0.1~0.2之间的随机数
cout << "r0 = " << r0 << ", r1 = " << r1 << ", r2 = " << r2 << endl;
cout <<"RAND_MAX = " << RAND_MAX << endl;
return 0;
}
输出
2^8 = 256
round(25.51) = 26
floor(25.997) = 25
ceil(25.01) = 26
sqrt(9) = 3
r0 = 41, r1 = 67, r2 = 0.11933
RAND_MAX = 32767
C3.8自定义函数
#include<iostream>
using namespace std;
float costCompute(int iStart, int iEnd)//返回值类型:float
{
int iConsume = iEnd -iStart;
return iConsume * 0.85f;
}
int main(){//先调用mian(),在main中遇到其他函数则进行其他函数的调用
float fElecFee1 = costCompute(1201,1786);
cout << "Electronic Power cost of Mr Zhang: " << fElecFee1 << endl;
return 0;
}
C3.9地址
#include<iostream>
using namespace std;
int main()
{
int i = 1,j = 2;
char c = 'c';
long double ld = 0.0;
// &i --> 获取对象i在内存中的地址
//地址,又称指针 pointer
printf("&i = %p, &j = %p, &c = %p, &ld = %p",&i,&j,&c,&ld);
//%p,pointer占位符
return 0;
}
输出
&i = 000000000061fe1c, &j = 000000000061fe18, &c = 000000000061fe17, &ld = 000000000061fe00
C3.10获取用户输入
- C语言风格
#include<stdio.h>
#include<math.h>
int main()
{
int iAge = 0,iHeight = 0;
float fWeight = 0;
printf("Please input your age,weight(kg):\n");
scanf("%d,%f",&iAge,&fWeight);
printf("Please input your height(cm):\n");
scanf("%d",&iHeight);
float fBMI = fWeight / pow((iHeight/100.0),2);
printf("Age = %d, weight(kg) = %.2f, height(cm) = %d,BMI = %.2f",iAge,fWeight,iHeight,fBMI);
return 0;
}
输出
Please input your age,weight(kg):
19,60
Please input your height(cm):
172
Age = 19, weight(kg) = 60.00, height(cm) = 172,BMI = 20.28
- C++语言风格
#include<iostream>
#include<math.h>
using namespace std;
int main()
{
int iAge {}, iHeight{};
float fWeight {};
cout << "Please input your age, weight(kg): "<< endl;
cin >> iAge >> fWeight;//用空格作区分
cout <<"Please input your height(cm): " << endl;
cin >> iHeight;
float fBMI = fWeight / pow((iHeight/100.0),2);
cout << "Age = " << iAge << ", weight = " << fWeight <<"kg, Height = "
<< iHeight << "cm, BMI = " << fBMI;
return 0;
}
输出
Please input your age, weight(kg):
19 60
Please input your height(cm):
172
Age = 19, weight = 60kg, Height = 172cm, BMI = 20.2812
注意(cin空格作区分):
Please input your age, weight(kg):
19,60
Please input your height(cm):
Age = 19, weight = 0kg, Height = 0cm, BMI = nan
C3.11常量
#include<iostream>
#include<math.h>
using namespace std;
#define PI 3.14159 //宏定义 预处理器
int main()
{
float r = 2;
const float CPI = 3.1415926;
cout << "Area of circle = " << PI*r*r << endl;
cout << "Area of circle = " << CPI*r*r << endl;
return 0;
}
C4分支与循环
C4.1ifelse
#include<iostream>
using namespace std;
//闰年 leap year
//四年一闰,百年不闰,四百年再闰
int main()
{
int iYear {};
cout << "Please enter the year: " << endl;
cin >> iYear;
if ((iYear%4==0 && iYear%100!=0) || (iYear%400==0)) //或者的表达
{
cout << iYear <<" is a leap year!" << endl;
}
else
{
cout << "An ordinary year." << endl;
}
return 0;
}
C4.2多分支
C4.3for循环
C4.3.1传统for循环
C4.3.2基于范围的for循环
#include<iostream>
using namespace std;
int main()
{
float fPrices[]{1020.23f,2928.12f,76.0f,992.0f};
int idx = 0;
cout <<"idx\t2/28\t2/19" << endl;
cout << "=======================" << endl;
for (auto x : fPrices)
cout << ++idx << "\t" << x <<"\t" << x*1.1f << endl;
return 0;
}
OUTPUT
idx 2/28 2/19
=======================
1 1020.23 1122.25
2 2928.12 3220.93
3 76 83.6
4 992 1091.2
C4.4break
C4.5continue
C4.6while
#include<iostream>
#include<string>
using namespace std;
int main()
{
string a = "";
while(a != "q")
{
getline(cin,a);//从cin读取一行-->a
cout << a << endl;
}
cout << "Bye, see you later!" << endl;
return 0;
}
读取数字的循环
C4.7do while
C4.8switch分支
#include<iostream>
#include<string>
using namespace std;
int main()
{
int iMonth{1};
cout << "Please input month number(1~12):"<<endl;
cin >> iMonth;
switch(iMonth){//括号里是整数表达式
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
cout << "There are 31 days in" << iMonth << "month." << endl;
break;//不能缺break,否则执行24行
case 4:
case 6:
case 9:
case 11:
cout << "There are 30 days in" << iMonth << "month." << endl;
break;
case 2:
cout << "There are 28/29 days in" << iMonth << "month." << endl;
break;
default:
cout << "Wrong Month Number!" << endl;
}
return 0;
}
C4.9goto
不要使用
C5数组和字符串
C5.1一维数组
字符串实质:数组
数组名本身:地址
#include<iostream>
using namespace std;
int main()
{
float scores[5] = {77,92.5,68,99,100};
scores[0] = 88;
cout << "sizeof(scores) = " << sizeof(scores) << endl;//数组名本身就是地址
cout << "scores = " << scores << endl;
cout << &scores[0] << "-" << &scores[1] << "-" << &scores[2] << "-" << &scores[3] << "-"
<< &scores[4] << endl;
float fSum = 0;
for (int i = 0;i<5;i++)
fSum += scores[i];
float fAvg = fSum / 5;
cout << "Average Scores = " << fAvg;
return 0;
}
输出
sizeof(scores) = 20
scores = 0x61fe00
0x61fe00-0x61fe04-0x61fe08-0x61fe0c-0x61fe10
Average Scores = 89.5
C5.2元素的下标访问
a [ i ] 的 地 址 = 首 元 素 的 地 址 + i × 单 个 元 素 的 地 址 = a + i × s i z e o f ( E l e m e n t T y p e ) a[i]的地址 = 首元素的地址 + i × 单个元素的地址 = a + i × sizeof(ElementType) a[i]的地址=首元素的地址+i×单个元素的地址=a+i×sizeof(ElementType)
- 注意不要越界!
C5.3数组的初始化
#include<iostream>
using namespace std;
int main()
{
short dummy[10] = {1,2};//剩余元素为0
short Amy[10] {};//全部初始化为0
short Sam[10] = {0};//同上
double Daming[10000];//元素值不确定
char d1[5] {'a',120,'k',',','?'};//C++可省略=,char:-127-128
char d2[] (12.0,'L',250);//报错,250超出储值范围,12.0类型收窄
double d[] = {1.2,3,2,888,99,12};
cout << sizeof(d) / sizeof(double) << endl;//元素个数 = 数组尺寸 / 元素尺寸
return 0;
}
输出
6
C5.A.2冒泡排序
C5.4C风格字符串
#include<stdio.h>
int main()
{
char s2[256] = "forest";//s2实质是类型为字符char的一维数组
char s1[] = "hello";//占六个字节,最后是\0
printf("s1 = %s, addr = %p, sizeof s1: %lld \n",s1,s1,sizeof(s1));
printf("s1 = %d %d %d %d %d %d\n",s1[0],s1[1],s1[2],s1[3],s1[4],s1[5]);
return 0;
}
输出
s1 = hello, addr = 000000000061FD0A, sizeof s1: 6
s1 = 104 101 108 108 111 0
#include<stdio.h>
int main()
{
char s2[256] = "forest";//s2实质是类型为字符char的一维数组
int i = 0;
while(s2[i]!=0){
s2[i] = s2[i] + ('A' - 'a');//'A'本质是整数,"A"本质是数组
i++;
}
printf("s2 = %s, addr = %p, sizeof s2 = %lld\n",s2,s2,sizeof(s2));
printf("'A' = %d, 'a' = %d",'A','a');
return 0;
}
OUTPUT
s2 = FOREST, addr = 000000000061FD00, sizeof s2 = 256
'A' = 65, 'a' = 97
#include<stdio.h>
#include<string.h>//进行字符串运算需包含string.h头文件
int main()
{
//C风格字符串运算
char s1[256] = "hello";
printf("s1 = %s, len = %lld\n",s1,strlen(s1));//strlen(接受指向字符的数组) -->len of string
char s2[512] = "world";
printf("strcmp(s1,s2) = %d\n",strcmp(s1,s2));//strcmp字符串逐个依次比较,s1<s2-->-1,s1>s2-->1,s1=s2-->0
char s3[512];
strcat(s1," ");//" "也是以\0为结尾的字符串,str concatenation字符串拼接,注意strcat很有可能过界!需要确保不会溢出
strcat(s1,s2);
strcpy(s3,s1);//string copy,把s1拷贝到s3
printf("s1 = %s, s2 = %s, s3 = %s.\n",s1,s2,s3);
return 0;
}
OUTPUT
s1 = hello, len = 5
strcmp(s1,s2) = -1
s1 = hello world, s2 = world, s3 = hello world.
C5.5CPP字符串
#include<iostream>
#include<string> //注意是string,不是string.h
using namespace std;
int main()
{
string s1 {"hello"};//会根据需要,自己改变自己的大小
for (unsigned int i=0;i<s1.size();i++)//string.size()成员函数, 注意是unsigned int(.size()返回size_t, 实质为unsigned int)
{
s1[i] += ('A'-'a');
}
cout << "s1 = " << s1 << ", size = " << s1.size() << ", sizeof(s1) = " << sizeof(s1) << endl;
//sizeof(s1) = 32: string对象大小固定,里面放的是管理机构,真正存放字符串内容的内存不在这32字节里面,在其外面。
return 0;
}
OUTPUT
s1 = HELLO, size = 5, sizeof(s1) = 32
#include<iostream>
#include<string> //注意是string,不是string.h
using namespace std;
int main()
{
string s1 {"Hello"};//会根据需要,自己改变自己的大小
string s2 = " world!";
string s3 = s1 + s2;
s1 += s2;
s2 = "Hello" + s2;
cout << "s1 = " << s1 <<", s2 = " << s2 << ", s3 = " << s3 << endl;
string s4 = "Life is a box of chocolates, you...";
cout << "s4.substr(17,10) = " << s4.substr(17,10) << endl;//s4.substr(17,10)从17开始取10个字符
auto iPos = s4.find("chocolates");
cout << iPos << endl;
s4.replace(iPos,10,"CHOCOLATES");//S4从17开始的10个字符替换成...
cout << "s2 = " << s4 << endl;
return 0;
}
输出
s1 = Hello world!, s2 = Hello world!, s3 = Hello world!
s4.substr(17,10) = chocolates
17
s2 = Life is a box of CHOCOLATES, you...
C5.6二维数组
a [ i ] [ j ] 的 地 址 = 首 元 素 的 地 址 + i × 单 行 元 素 的 尺 寸 + j × 单 个 元 素 的 尺 寸 = a + i × ( 单 个 元 素 的 尺 寸 × 单 行 元 素 个 数 ) + j × 单 个 元 素 的 尺 寸 = a + i × ( s i z e o f ( E l e m e n t T y p e ) × 列 数 ) + j × s i z e o f ( E l e m e n t T y p e ) a[i][j]的地址 = 首元素的地址 + i × 单行元素的尺寸 + j × 单个元素的尺寸 = a + i × (单个元素的尺寸 × 单行元素个数) + j × 单个元素的尺寸 = a + i × ( sizeof(ElementType) × 列数 ) + j × sizeof(ElementType) a[i][j]的地址=首元素的地址+i×单行元素的尺寸+j×单个元素的尺寸=a+i×(单个元素的尺寸×单行元素个数)+j×单个元素的尺寸=a+i×(sizeof(ElementType)×列数)+j×sizeof(ElementType)
#include<iostream>
#include<string> //注意是string,不是string.h
using namespace std;
int main()
{
//二维数组
float scores[4][5]={//四行五列的二维数组
{67,98,77,80,86},
{56,89,45,76,63},
{78,69,96,67,99},
{88,19,78,55,68}
};//不要落掉;
scores[1][2] = 100;//45-->100
printf("scores = %p, sizeof(scores) = %lld\n",scores,sizeof(scores));
return 0;
}
输出
scores = 000000000061fdd0, sizeof(scores) = 80
- C/C++不会对二维数组的越界访问进行检查,保证只访问属于该数组的元素,是程序员的职责。
#include<iostream>
#include<string> //注意是string,不是string.h
using namespace std;
int main()
{
//二维数组
float scores[4][5]={//四行五列的二维数组
{67,98,77,80,86},
{56,89,45,76,63},
{78,69,96,67,99},
{88,19,78,55,68}
};//不要落掉;
printf("scores[0~3] = %p %p %p %p\n",scores[0],scores[1],scores[2],scores[3]);//全部相隔二十个字节
printf("&scores[1][0~2] = %p %p %p\n",&scores[1][0],&scores[1][1],&scores[1][1]);//元素按照顺序依次存储
printf("&scores[1~2][1] = %p %p\n",&scores[1][1],&scores[2][1]);//每行相隔20
float fSum = 0;
for (unsigned int j=0;j<5;j++)
fSum += scores[1][j];
float fAvg = fSum / 5;
printf("Avg of score[1][0~4] = %.2f",fAvg);
return 0;
}
OUTPUT
scores[0~3] = 000000000061fdc0 000000000061fdd4 000000000061fde8 000000000061fdfc
&scores[1][0~2] = 000000000061fdd4 000000000061fdd8 000000000061fdd8
&scores[1~2][1] = 000000000061fdd8 000000000061fdec
Avg of score[1][0~4] = 65.80
C5.7多维数组
#include<iostream>
#include<string> //注意是string,不是string.h
using namespace std;
int main()
{
//多维数组
short a[2][2][3] =
{
{
{0,1,2},
{10,11,12}
},
{
{100,101,102},
{110,111,112}
}
};
printf("a = %p\nsizeof(a) = %lld\n",a,sizeof(a));
printf("a[1][1][1] = %d",a[1][1][1]);
return 0;
}
C6指针和引用
C6.1指针
指针pointer 是一个值为内存地址的对象。
#include<iostream>
#include<string> //注意是string,不是string.h
using namespace std;
int main()
{
//指针pointer
int a = 9999,*p;//p是一个指向整数对象的指针对象
int* p1;//可以这样定义
p = &a;
printf("before: a = %d, *p = %d\n",a,*p);//*p:p是地址,*p是p指向的值
a++;
*p = *p + 100;
printf("after: a = %d, *p = %d\n",a,*p);//p始终是a的地址
printf("&a = %p, p = %p, sizeof(p) = %lld\n",&a,p,sizeof(p));//指针大小取决于你的64位/32位
printf("&p = %p",&p);//指针(也是一个对象/变量)的地址
/*
变量a:类型是int,值是9999
变量p,也是一个对象(变量):类型是int*(指向整数对象的指针对象),
值是a的地址
*/
return 0;
}
OUTPUT
before: a = 9999, *p = 9999
after: a = 10100, *p = 10100
&a = 000000000061fe1c, p = 000000000061fe1c, sizeof(p) = 8
&p = 000000000061fe10
变量名 | 类型 | 值 | 内存地址 |
---|---|---|---|
a | int | 9999 | 000000000061fe1c |
p | int* | 000000000061fe1c | 00000000061fe10 |
C6.2空指针
当一个指针对象的值为0时,该指针事实上不能指向任何对象,我们称该指针为空指针(null pointer)
#include<iostream>
#include<string> //注意是string,不是string.h
using namespace std;
int main()
{
double d = 3.14;
double* p = NULL;//double* p = (double*)0;无法对*p进行操作;不可以对空指针应用间接操作符(*)
printf("p = NULL = %p\n",p);
p = &d;
printf("p = &d = %p, *p = d = %f",p,*p);
return 0;
}
OUTPUT
p = NULL = 0000000000000000
p = &d = 000000000061fe10, *p = d =3.140000
C++空指针:nullptr.
可以转换为任意指针类型的对象,其值为0,它既可以赋值给int*,也可以赋值给char*,还可以赋值给unsigned long long*类型的对象。
#include<iostream>
#include<stdio.h>
using namespace std;
int main()
{
char c {'c'};
char* p {nullptr}; //str::nullptr_t --> C++空指针类型
printf("p = nullptr = %p\n",p);
p = &c;
printf("p = &c = %p, c = %c, *p = %c",p,c,*p);
return 0;
}
OUPUT
p = nullptr = 0000000000000000
p = &c = 000000000061fe17, c = c, *p = c
C6.3指针的简单应用
- 传值调用:产生克隆体,不会对函数外部的值产生影响。
- 传指针调用:希望在函数内部改变函数外部的值;如果传入的参数非常大(图片等)以免产生克隆体
#include<iostream>
#include<string>
using namespace std;
void swap1(int a,int b);
void swap2(int* a,int *b);
int main()
{
int m = 2,n = 7;
swap1(m,n);//传值调用 call by value
cout << "after swap1: m = "<< m << ", n = " << n << endl;
swap2(&m,&n);//传指针调用 call by pointer
cout << "after swap2: m = "<< m << ", n = " << n << endl;
return 0;
}
void swap1(int a,int b)//a,b是m,n的复制品,对ab的操作不会改变mn
{
int t = a;
a = b;
b = t;
}
void swap2(int* a,int *b)
{
int t = *a;
*a = *b;
*b = t;
}
OUTPUT
after swap1: m = 2, n = 7
after swap2: m = 7, n = 2
C6.4指针与数组
#include<iostream>
#include<iomanip>//setprecision()
using namespace std;
int main()
{
float scores[5] = {55,66,77,88,99};
float* p1 = scores;//地址长度均为8,指向的对象的长度不同
cout << "sizeof(scores) = " << sizeof(scores) <<", sizeof(p1) = " << sizeof(p1) << endl;
float* p2 = new float;//向操作系统申请内存
if (p2==NULL)//当无可分配空间时,返回NULL
exit(EXIT_FAILURE);//宏定义,程序运行出错
float fSum = 0;
for (unsigned int i=0;i<5;i++)
{
p2[i] = p1[i];//可以将p1当作数组名来用
fSum += p2[i];
}
cout << fixed << setprecision(2) << fSum/5 << endl;
delete p2;//new和delete要同时使用!
return 0;
}
OUTPUT
sizeof(scores) = 20, sizeof(p1) = 8
77.00
C6.5指针运算
#include<iostream>
using namespace std;
int main()
{
float* p = new float;
if(p==NULL)
exit(1);
cout << "p = "<< p << ", p+1 = " << p+1 <<", p+3 = "<< p+3 << endl;//+1:+一个浮点数的大小,移动到下一个浮点数
for(int i=0;i<10;i++)
{
*(p++) = i;//先取值,再移动到下一个浮点数
}
p-=10;//退回40个字节,指向第0个元素
cout << "p[0] = " << *p << ", p[3] = " << *(p+3) << endl;
delete p;
return 0;
}
output
p = 0x731e70, p+1 = 0x731e74, p+3 = 0x731e7c
p[0] = 0, p[3] = 3
#include<iostream>
#include<ctype.h>
using namespace std;
int main()
{
char s[] = "Mary has 4 lambs.";//18个字节,末尾有/0
char* p = s;//数组名与指针相同,但数组名不是指针
while (*p!=0)
{
if(islower(*p))//ctype-->是否是小写
*p += ('A'-'a');
p++;//移到下一个字节
}
cout << "s = " << s << endl;
return 0;
}
output
s = MARY HAS 4 LAMBS.
C6.6指向指针的指针
#include<iostream>
using namespace std;
int main()
{
int a = 100;
int* p = &a;
int** pp = &p;
cout << "&a = " << &a << ", p = " << p << endl;
cout <<"&p = "<< &p << ", pp = " << pp << endl;
cout << "&pp = " << &pp << endl;
cout <<"Before: a = " << a << ", *p = " << *p <<", **pp = " << **pp << endl;//**pp = a
a++;
(*p)++;
(**pp)++;
cout <<"After: a = " << a << ", *p = " << *p <<", **pp = " << **pp << endl;//**pp = a
return 0;
}
OUTPUT
&a = 0x61fe1c, p = 0x61fe1c
&p = 0x61fe10, pp = 0x61fe10
&pp = 0x61fe08
Before: a = 100, *p = 100, **pp = 100
After: a = 103, *p = 103, **pp = 103
C6.7main()的参数
没大听懂,挠头.gif
C6.8指针与常量
#include<iostream>
using namespace std;
int main()
{
const int a = 10;//常量a=10
int*p1 = &a;//错误,可能*p1=3
const int *p2 = &a;//正确,p2指向常量
int b=10;
const int *p3 =&b;//正确,不能通过p3修改它指向的变量,p2是变量,可以指向b,可以指向a,例如不能*p3 += 2
int c=10,d=11;
const int* const p4 =&c;//正确,不能通过p4修改c,并且p4是常量
}
C6.9引用
**引用(Reference)**的实质是自解析的指针
#include<iostream>
#include<stdio.h>
using namespace std;
int main()
{
int iRabbits = 100;
int& iBunnies = iRabbits;//整数型的引用,相当于取了一个别名,但是iBunnies也是一个指针,只是自解析了
//翻译:iBunnies内部的指针 = &iRabbits
//引用不允许再把iBunnies指向其他变量,只能指向iRabbits
printf("iRabbits = %p, &iBunnies = %p\n",&iRabbits,&iBunnies);
iRabbits += 10;//修改的同一块内存
iBunnies += 5;//修改的同一块内存
//翻译:(*iBunnies内部的指针)+= 5
cout << "iRabbits = " << iRabbits << ", iBunnies = " << iBunnies <<endl;
int a =3,b=4;
int* p = &a;
p = &b;//指针可以改变指向哪一个地址(变量)
int c = 3,d = 4;
int& r = c;//必须初始化,不能空
r = d;//r依然指向c,此行令c=d
cout << c << d << r << endl;
float e = 3.14f;
const float& f = e;//f是常量,修改e可以,不能通过f修改e,但可以修改e修改f
e += 1.0;
cout << e << " "<< f << endl;
return 0;
}
输出
iRabbits = 000000000061fdf4, &iBunnies = 000000000061fdf4
iRabbits = 115, iBunnies = 115
444
4.14 4.14
#include<iostream>
#include<stdio.h>
using namespace std;
int main()
{
float fPrices[] = {1.0f,10.0f,100.0f};
for(auto x:fPrices)//这里的x是fprices中元素的复制品
{
x*=1.2f;
}
for(auto x:fPrices)
cout << x << endl;
for(auto& x:fPrices)//这里的x是fprices中元素的引用,是指同一个地址的同一个元素
{
x*=1.2f;
}
for(auto x:fPrices)
cout << x << endl;
return 0;
}
输出
1
10
100
1.2
12
120
C6.10引用与函数
#include<iostream>
#include<stdio.h>
using namespace std;
//传引用调用call by reference
//能用引用,就不用指针
void swap1(float& a,float &b)
{
printf("&a = %p,&b = %p\n",&a,&b);
float t = a;
a = b;
b = t;
}
int main()
{
float m{1.1f},n{9.9f};
printf("&m = %p,&n = %p\n",&m,&n);
swap1(m,n);//事实上是传地址
cout << "m = " << m <<",n = " << n << endl;
return 0;
}
输出
&m = 000000000061fe1c,&n = 000000000061fe18
&a = 000000000061fe1c,&b = 000000000061fe18
m = 9.9,n = 1.1
#include<iostream>
#include<stdio.h>
using namespace std;
//传引用调用call by reference
//能用引用,就不用指针
void swap1(float& a,float &b)
{
printf("&a = %p,&b = %p\n",&a,&b);
float t = a;
a = b;
b = t;
}
double getCircleArea(const double& r)
{
return 3.1415926*r*r;
}
int main()
{
float c = 3.0f;
swap1(c,c+1.0f);//错误,c的内存是确定的,c+1.0f是临时对象,临时对象一般被认为是const,用完即弃
double dArea = getCircleArea(7.6f);//正确,7.6f虽然是临时对象,但是getCircleArea()参数是const double
return 0;
}
C7函数与抽象
C7.1抽象的魅力
C7.2函数的定义
C7.3函数与一维数组
#include<iostream>
#include<stdio.h>
using namespace std;
//函数于一维数组
float avg(const float a[],const unsigned int n)//const(1)本函数功能是读取数组元素,不应该修改参数数组;const(2)不应该修改该数组的元素数
//const float *a == const float a[]
//数组元素个数:unsigned int
{
printf("a = %p\n",a);
float fSum = 0;
for(unsigned int i=0;i<n;i++)
{
fSum += a[i];
}
return fSum/n;
}
int main()
{
float scores[5]{50,60,70,80,90};
printf("scores = %p\n",scores);
float fAvg = avg(scores,5);//把一维数组作为参数时,传递的是首元素地址
printf("average = %f\n",fAvg);
return 0;
}
输出
scores = 000000000061fe00
a = 000000000061fe00
average = 70.000000
C7.4函数与二维数组
#include<iostream>
#include<stdio.h>
using namespace std;
//函数与二维数组
float avg(const float a[][3],const unsigned int n)//const float必须指明第一维,第零维可以不知道,
//const float a[][3] == const float (*a)[3]-->如何理解:a是一个指针;a所指向的对象为包含3个const float的一维数组。
//更推荐第一种形式。
//const float * a[3] -->a是一个三个元素的一维数组,每个元素都是一个指向const float的指针
{
float fSum=0;
for(unsigned int i=0;i<n;i++)
for(unsigned int j=0;j<3;j++)
fSum += a[i][j];
return fSum/(n*3.0);
}
int main()
{
float scores[2][3] = {
{50,60,70},
{80,90,100}
};
float fAvg = avg(scores,2);
}
C7.5变量的作用域
作用域:scope
局部变量:local variable(块作用域:block scope)
块:一对花括号内
#include<iostream>
#include<stdio.h>
using namespace std;
//变量的作用域
float PI=3.1415926;//文件作用域 file scope,一旦局部作用域中出现同名,则在局部作用域中使用的是局部定义的那一个
float getCircleArea(float r){
printf("getCircleArea:&r = %p\n",&r);
return PI*r*r;
}
int main()
{
float r = 4;
printf("main:&r = %p\n",&r);
float fArea = getCircleArea(r);
printf("area = %f",fArea);
return 0;
}
输出
main:&r = 000000000061fe18
getCircleArea:&r = 000000000061fdf0
area = 50.265480
C7.6递归
待做
C7.A.1算法-汉诺塔
待做
C7.7函数指针
#include<iostream>
#include<stdio.h>
using namespace std;
//函数指针
int add(int a,short b)
{
printf("add here\n");
return a+b;
}
int main()
{
float f = 3.3f;
int c = 33;
printf("add = %p,&f = %p,&c = %p\n",add,&f,&f);//add本身就是地址
int(*pf)(int,short) = NULL;//定义了一个指向函数的指针,pf是指向一个函数的地址,接受一个int和一个short为变量
//注意pf是一个对象
//int* pf(int short) 一个名为pf的函数,接受一个int和一个short为参数,返回一个指向整型的指针
pf = add;
printf("pf = %p,&pf = %p\n",pf,&pf);//pf = add
int d = pf(3,2);//pf(3,2) = add(3,2)
printf("3+2=%d",d);
return 0;
}
输出
add = 00000000004015a4,&f = 000000000061fe14,&c = 000000000061fe14
pf = 00000000004015a4,&pf = 000000000061fe08
add here
3+2=5
#include<iostream>
#include<stdio.h>
using namespace std;
//函数指针
int add(int a,short b)
{
printf("add here\n");
return a+b;
}
int main()
{
int(*pf)(int,short) = NULL;
pf = add;
int d = pf(3,2);//pf(3,2) = add(3,2)
int e = (*pf)(3,2);// == int d = pf(3,2) == add(3,2)//我更喜欢这种
printf("3+2=%d\n",d);
printf("3+2=%d",e);
return 0;
}
输出
add here
add here
3+2=5
3+2=5
待做:排序
C7.8默认值参数
#include<iostream>
#include<string>
using namespace std;
int add(int a,int b,int c=0,int d=0);//默认值参数只能写在声明中而不是定义中,如果兼具就可以
int main()
{
cout << " 1+2 = " << add(1,2) << endl;//批量复制:shift+alt+↓
cout << " 1+2+3 = " << add(1,2,3) << endl;
cout << " 1+2+3+4 = " << add(1,2,3,4) << endl;
return 0;
}
int add(int a,int b,int c,int d)//后面的定义不可含默认值参数
{
return a+b+c+d;
}
C7.9内联函数
函数调用是需要花费额外的CPU和内存资源
#include<iostream>
#include<string>
using namespace std;
inline static float average(float* a,int n)//inline-->内联;static-->数据类型
{
float fSum=0;
for(int i=0;i<n;i++)
fSum += a[i];
return fSum/n;
}
int main()
{
float values[] = {0,1,2,3,4,5,6,7,8,9};
float v4 = average(values,4);
printf("v4 = %f\n",v4);
float v7 = average(values,7);
printf("v7 = %f\n",v7);
float v10 = average(values,10);
printf("v10 = %f\n",v10);
return 0;
}
使用内联的情况:
递归不适宜
待补充
#include<iostream>
#include<bitset>
using namespace std;
inline void setBit(unsigned int& v,int bit)//置位:把32位无符号整数v的第bit位置成1
/*
为什么适宜内联:
程序可读性强
不希望函数调用使代码变慢
*/
{
v |= (0x01 << bit);//注意取|
}
int main()
{
unsigned int v = 0x00000000;//=0
cout <<"before setBit: " << bitset<32>(v) << endl;//bitset(类型):把一个unigned int -->字符串格式的二进制
setBit(v,0);
setBit(v,31);
v |= (0x01 << 11);
cout << "after setBit: " << bitset<32>(v) << endl;
return 0;
}
C7.10函数名重载
编译器通过名字装饰 name decoration 进行函数名重载
函数名重载只能依赖于形参的个数、类型和顺序,不能依赖于返回值类型
#include<iostream>
#include<string>
using namespace std;
void swapObject(float& a,float& b){
auto t = a;
a = b;
b = t;
}
void swapObject(int& a,int& b){
auto t = a;
a = b;
b = t;
}
void swapObject(string& a,string& b){
auto t = a;
a = b;
b = t;
}
int main()
{
float a1 = 1.1f,b1 = 2.2f;
swapObject(a1,b1);
cout << " a1 = " << a1 << ", b1 = " << b1 << endl;
int a2 = 1,b2 = 2;
swapObject(a2,b2);
cout << " a2 = " << a2 << ", b2 = " << b2 << endl;
string a3 = "you",b3 = "I love";
swapObject(a3,b3);
cout << " a3 = " << a3 << ", b3 = " << b3 << endl;
return 0;
}
C7.11模板函数
#include<iostream>
#include<string>
using namespace std;
//模板函数template function
template<typename T>
void swapObject(T& a,T& b){
auto t = a;
a = b;
b = t;
}
int main()
{
char c1{'a'}, c2{'z'};
swapObject(c1,c2);//实际上为:swapObject<char>(c1,c2)
cout << "c1 = " << c1 << ", c2 = " << c2 << endl;
return 0;
}
C13 类与抽象
C13.1 面向对象
Cpp-补充指南
1.数组储存
- 换行输入
- 空格输入
2. #include<vector>
- Vector的能力
1.Vector支持随机访问。
2.在末端添加或删除元素,vector的效率相当好;在前端/中部安插或删除元素,效率不好。
- Vector的构造函数和析构函数
- Vector的非更易型操作
1.读入一行整数
while(cin>>d[i][j])
{
j++;
if (getchar() == '\n')//注意这里要加‘’,而不是“”
break;
- Vector的更易型操作
1.找到某特定元素并删除
vector<int>::iterator it = find(NumberArray.begin(), NumberArray.end(), iFind); //第一次查找
while (it != NumberArray.end()) //判断是否找到
{
it = NumberArray.erase(it); //找到了删除 并 移动 it 指向下一个位置
//错误写法: NumberArray.erase(it); it++; //原因vector中元素被删除之后it已经失效,不能进行++操作
it = find(it, NumberArray.end(), iFind); //继续查找
}
3. #include<string>
- string.substr()
- find()
4.#include<iomanip>
cout << fixed << setprecision(n) <<