大一下C++学习记录-简洁版本

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
变量名类型内存地址
aint9999000000000061fe1c
pint*000000000061fe1c00000000061fe10

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) << 

5.#include<algorithm>

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: 《算法笔记》是由胡凡编写的一本关于算法学习的教材,它最初以C/C++为主要编程语言。这本教材主要面向想要学习算法的初学者,以及希望进一步提升算法能力的人群。 《算法笔记》的内容广泛而且深入,涵盖了很多算法的基础知识和主要思想,如递归、排序、查找、图论、动态规划等。通过学习这本教材,读者可以掌握这些算法的基本原理和实现方法,提高解决实际问题的能力。 该教材有几个特点:首先,它提供了很多例子和习题,帮助读者巩固所学的知识;其次,它介绍了很多常用的数据结构,如数组、链表、栈、队列等,读者可以通过学习这些数据结构更好地理解和应用算法;最后,它还介绍了一些高级主题,如高级数据结构、算法优化等,这些内容对于进一步提升算法水平非常有帮助。 《算法笔记》是一本入门级的教材,因此在阅读时需要一些基本的编程知识和逻辑思维能力。该教材的语言简洁明快,适合作为学习参考书,同时也可以作为算法竞赛的辅助教材。 总而言之,《算法笔记》是一本很好的算法学习教材,它以C/C++为编程语言,全面介绍了算法的基本知识和常用方法,适合想要学习算法的初学者。无论是学术研究还是实际应用,阅读《算法笔记》都能提升算法能力,并为进一步学习和应用算法打下坚实的基础。 ### 回答2: 《算法笔记 胡凡 c/c 快速入门pdf》是一本介绍算法和C/C++编程语言的入门书籍。该书的作者是胡凡,它主要规划了算法的学习路径以及基本的C/C++编程语言。这本书适合初学者快速入门,对于想要系统学习算法和C/C++编程的人来说是一本不错的选择。 这本书的内容非常系统和全面。它以算法和数据结构为基础,包括基本排序、查找、图论等算法的介绍和实践,让读者能够快速掌握这些算法的原理和实现方法。同时,它还介绍了C/C++语言的基础知识和编程技巧,帮助读者理解和运用这些知识。 书中每章都有一些练习题,帮助读者巩固所学的知识。同时,每个章节末尾还提供了一些进阶的题目和参考答案,供读者深入学习和自我检测。这样的设计能够帮助读者更好地理解和掌握所学的内容。 总的来说,《算法笔记 胡凡 c/c 快速入门pdf》是一本很好的算法和C/C++入门书籍。它能够帮助读者快速了解算法和数据结构的基础知识,并学会使用C/C++语言进行编程。无论是对于想要入门算法和C/C++编程的初学者,还是已经有一定基础的读者,这本书都是一个很好的选择。 ### 回答3: 《算法笔记:胡凡C/C++快速入门PDF》是一本很棒的入门算法书籍。这本书主要介绍了常用的数据结构与算法,并通过C/C++语言来实现这些算法。 首先,这本书非常适合算法初学者。它从基础的数据结构开始讲解,如数组、链表、栈和队列,然后逐渐引入更复杂的数据结构,如二叉树、图和堆。此外,书中还介绍了常用的排序和查找算法,如冒泡排序、快速排序、二分查找等。每个算法都配有具体的代码实现和详细的解释,帮助读者理解算法的原理和应用。 其次,这本书的学习资料丰富。书中提供了很多例题和习题,读者可以通过实践来巩固所学的知识。此外,书中还介绍了一些常见的算法优化技巧和设计思路,提供了一些高效解决问题的方法和思考方式。 最后,这本书的编写风格简明易懂。作者通过清晰的语言和简洁的代码,将复杂的算法问题简化为易于理解的部分。不论是对于算法初学者还是对于有一定编程基础的读者,这本书都是一本很好的学习资料。 总而言之,《算法笔记:胡凡C/C++快速入门PDF》是一本很好的入门算法书籍。它适合初学者学习和理解常用的数据结构与算法,通过具体的代码实现和详细的解释帮助读者掌握算法的原理和应用。无论是编程初学者还是有一定基础的读者,都可以从这本书中获得丰富的知识和实践经验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值