c++基础知识点

目录

1.一个简单c++代码

 2.命名空间

2.1 域

2.2 自定义命名空间

2.3 命名空间使用

2.4 命名空间的展开

3.c++的输入输出

4.缺省函数

5.函数重载

6.引用

6.1 引用基础用法

6.1.1 引用的使用方法

 6.1.2 指针的引用

6.2 引用的常用方法

6.2.1 做函数的参数

6.2.2 引用的错误使用

6.3 引用和指针对比

7.内联函数 

7.1宏函数

7.2 内联函数

8. auto关键字

8.1 auto使用规则

8.2 auto不能使用的场景

9. 基于范围的for循环

9.1 范围for的语法

9.2 auto使用条件

10. 指针空值nullptr(C++11)

10.1 C++98中的指针空值


1.一个简单c++代码

#include<iostream>
using namespace std;
int main()
{
    cout<<"hello world"<<endl;
    return 0;
}

 这个代码类似于我们学习c语言中“hello world”。

 2.命名空间

2.1 域

域就是范围的意思,也是一个空间。它分为全局和局部,如

#include<iostream>
using namespace std;
int x=0;
int main()
{
    int x=10;
    return 0;
}

x=0就是在全局域里的变量,x=10是局部的变量。变量的调用是局部优先,局部没有的话就在全局域里去寻找调用。

2.2 自定义命名空间

当我们需要创建多个同名变量时,可以自命名多个域,即自定义空间。

#include<iostream>
using namespace std;
int x=0;
namespace name1//namespace+域名
{
    int x=5;
}
int main()
{
    int x=10;
    return 0;
}

自定义空间里可定义变量和类,以及函数,甚至再定义一个空间。

定义多个同名空间:

#include<iostream>
using namespace std;
int x=0;
namespace name1//namespace+域名
{
    int x=5;
}
namespace name1
{
    int y=10;
    x=1;
}
int main()
{
    int x=10;
    return 0;
}

定义多个同名空间,编译器会将他们整合成一个空间。 

2.3 命名空间使用

我们要调用空间里的变量时,需要用::符号。

#include<iostream>
using namespace std;
int x=0;
namespace name1//namespace+域名
{
    int x=5;
}
int main()
{
    int x=10;
    int y=name1::x;
    return 0;
}

name1::x,::前跟空间名,::后跟命名空间里要调用的变量。

::前不跟空间名的话,默认的是在全局域里调用。

2.4 命名空间的展开

我们要使用命名空间里的变量时,需要使用::符号,可以将命名空间展开成全局空间。关键词using namespace +空间名。

#include<iostream>
using namespace std;
int x=0;
namespace name1//namespace+域名
{
    int x=5;
}
using namespace name1;
int main()
{
    int y=x;
    return 0;
}

此时那么name1空间被展开成全局域,y=x时,局部没有变量x,在全局中有x=5.

命名空间局部展开:

#include<iostream>
using namespace std;
int x=0;
namespace name1//namespace+域名
{
    int x=5;
    int y=1;
    int z=2;
}
using name1::z;
int main()
{
    int n=z;
    return 0;
}

如上代码using name1::z就是只把name1空间里面的z展开成为全局变量,其他仍在命名空间内。

3.c++的输入输出

我们看文章开头的代码:

#include<iostream>
using namespace std;
int main()
{
    cout<<"hello world"<<endl;
    return 0;
}

第一行#include<iostream>是C++中的头文件,它包含了我们需要输入输出的函数。

第二行using namespace std就是我们所讲的命名空间展开,std是iostream头文件里的命名空间。

 cout<<"hello world"<<endl这个代码中cout类似于c语言中printf,<<是流插入符号,可以将变量类型输出到控制台中,end等同于'/n'就是换行。这个代码如果用c语言写就是printf("%s","hello world");printf需要说明变量类型,而<<可以自动识别变量类型。

int i,ch;
cin>>i>>ch;

 这个代码类似于scanf,>>是流提取符号,cin>>就是从键盘中输入数据。cin也是std空间里的一个函数。

4.缺省函数

c++引入了一种缺省函数:

int Add(int a=0,int b=0)
{
    return a+b;
}

缺省参数就是默认参数,当我们调用函数时不传参数,就默认参数值为我们设计的值:

int Add(int a=0,int b=0)
{
    return a+b;
}
int main()
{
    int c=Add();//return 0+0;
}

此时默认a和b是我们设定的值。

半缺省:

我们设计缺省函数时,可以部分参数缺省:

int Add(int a,int b,int c=0)
{
    return a+b+c;
}
int main()
{
    int c=Add();//return 0+0;
}

半缺省规则:缺省必须从右往左连续缺省,不能从左往右,也不能跳跃缺省。

半缺省函数的调用:传参时必须从左往右传,

nt Add(int a,int b,int c=0)
{
    return a+b+c;
}
int main()
{
    int c=Add(5,1);//a=5,b=1,c是缺省值默认为0;
}

5.函数重载

在c语言中不允许函数名相同,但c++中可以。

要求:函数名相同,参数不同,构成重载函数。

int Add(int a,int b)
{
    return a+b;
}

double Add(double a,double b)
{
    return a+b;
}

当我们调用函数时,系统会自动调用对应类型参数的重载函数。

int Add(int a,int b)
{
    return a+b;
}

double Add(double a,double b)
{
    return a+b;
}

int main()
{
    Add(2,3);//调用int Add(int a,int b)
    Add(2.1,2.2);//调用double Add(double a,double b)
}

6.引用

6.1 引用基础用法

6.1.1 引用的使用方法

引用即给变量起别名,用符号&:

int a;
int& b=a;

即b是a的别名,a和b是同一个变量,只是名字不一样:

通过a和b地址我们发现是相同的。

 6.1.2 指针的引用
int* p;
int*& q= p;

即指针q是p指针的别名。 

引用必需初始化,且不能改变指向:

int b;
int& a;
a=b;


引用时必须初始化,所以这个代码是错误的。 

int b,c;
int& a=b;
a=c;

 这个代码不是改变引用a指向c,而是将c赋值给a或者说是给b。

6.2 引用的常用方法

6.2.1 做函数的参数
void swap(int& x,int& y)
{
    int s;
    s=x;
    x=y;
    y=s;
}

int main()
{
    int a=4;
    int b=0;
    swap(a,b);
}

x和y分别是a和b的引用,因此交换x和y,就是交换a和b。

6.2.2 引用的错误使用

临时变量出了作用域就销毁,不能引用返回。

int& func()
{
    int a=0;
    return a;
}

返回值是a的别名,a被销毁了,所以返回值是野值。

6.3 引用和指针对比

语法:

1.引用时别名,语法上不开空间,底层是用指针实现的要开空间;指针语法上需要开空间,底层要开空间。

2.引用必须初始化,指针可以不用初始化。

3.引用不可以改变指向,指针不可改变指向。

4.引用没有空引用,相对更安全;指针有空指针,容易出现野指针。

5.sizeof下引用是引用类型的大小;指针的大小32位下位4字节。

6.引用加加即引用的实体加一;指针加加即指针先后偏移一个指向类型的大小。

7.有多级指针,没有多级引用。

底层:

汇编层面上,没有引用,都是指针,引用编译后也转换成了指针。

7.内联函数 

7.1宏函数

宏是一种替换,它是在预处理阶段进行的。

 我们要写一个加法宏函数:

#define Add(a,b) ((a)+(b))

宏的缺点:

1.语法复杂,坑很多,不容易控制。

2.不能调试

3.没有类型检查                                                                                                                                 

7.2 内联函数

函数在调用时,会建立栈帧,而内联函数实在调用的地方进行展开,没有建立栈帧的开销,因此提升程序运行速率。

关键词inline,在调用函数时,在函数前加上inline,就会在编译时用函数体替代函数调用。

void swap(int& x,int& y)
{
    int s;
    s=x;
    x=y;
    y=s;
}

int main()
{
    int a=4;
    int b=0;
    inline swap(a,b);
/* 
swap(a,b)
{
    int s;
    s=a;
    a=b;
    b=s;
} 被展开*/
}

缺点:函数展开会增加代码存储大小变大。

比如一个函数100行,调用1w次,内联函数占100*1w行,而不内联的话只占1w+100行。

特性:

1. 内联函数是以空间换时间的方法。

2. inline对于编译器而言只是一个建议:将函数规模较小,不是递归,且频繁调用的函数采用inline修饰,不满足的函数,编译器会忽略inline特性。

3. inline在编译器debug模式下不展开函数。

8. auto关键字

8.1 auto使用规则

1. auto定义变量时可以自动推导,赋值变量的类型。

int a;
void f1(int a,int b)
{
    
}


int main()
{
    int a;

    auto f=a;//f类型为
    auto pf=&a;//pf类型为int*
    auto& f=a;//f类型为int,是a的别名
    void(*pf1)(int,int)=f1;//void(*pf1)(int,int)是函数指针,非常的复杂
    auto pf1=f1;//pf1也是和上面一样的函数指针
}

2.  在同一行定义多个变量

void TestAuto()
{
    auto a = 1, b = 2; 
    auto c = 3, d = 4.0;  // 该行代码会编译失败,因为c和d的初始化表达式类型不同
}

8.2 auto不能使用的场景

1. auto不能作为函数的参数

// 此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
void TestAuto(auto a)
{}

2. auto不能直接用来声明数组

void TestAuto()
{
    int a[] = {1,2,3};
    auto b[] = {4,5,6};
}

9. 基于范围的for循环

9.1 范围for的语法

在c语言里我们遍历一个数组可以:

void TestFor()
{
int array[] = { 1, 2, 3, 4, 5 };
for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)
     array[i] *= 2;
for (int* p = array; p < array + sizeof(array)/ sizeof(array[0]); ++p)
     cout << *p << endl;
}

在c++里,for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围。

int array[] = { 1, 2, 3, 4, 5 };
for(int a:array)
{
    cout<<a<<endl;
}

这个代码,a为array赋值的变量,它从array数组下标为0开始遍历直到结束。

范围for配合auto的使用:

void TestFor()
{
int array[] = { 1, 2, 3, 4, 5 };
for(auto& e : array)
     e *= 2;
for(auto e : array)
     cout << e << " ";
return 0;
}

 代码可以实现对array进行*2。

auto& e是对迭代范围的引用,因此对e修改就是对array修改;而auto e是对迭代范围值的拷贝,因此修改的话,只能修改e,不能修改array。

9.2 auto使用条件

1. for循环迭代的范围必须是确定的

对于数组而言,就是数组中第一个元素和最后一个元素的范围;对于类而言,应该提供begin和end的方法,begin和end就是for循环迭代的范围。

注意:以下代码就有问题,因为for的范围不确定

void TestFor(int array[])
{
    for(auto& e : array)
        cout<< e <<endl;
}

10. 指针空值nullptr(C++11)

10.1 C++98中的指针空值

NULL实际是一个宏,在传统的C头文件(stddef.h)中,可以看到如下代码:

#ifndef NULL
#ifdef __cplusplus
#define NULL   0
#else
#define NULL   ((void *)0)
#endif
#endif

可以看到,NULL可能被定义为字面常量0,或者被定义为无类型指针(void*)的常量。不论采取何种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦,比如:

void f(int)
{
 cout<<"f(int)"<<endl;
}
void f(int*)
{
 cout<<"f(int*)"<<endl;
}
int main()
{
 f(0);
 f(NULL);
 f((int*)NULL);
 return 0;
}

程序本意是想通过f(NULL)调用指针版本的f(int*)函数,但是由于NULL被定义成0,因此与程序的初衷相悖。
在C++98中,字面常量0既可以是一个整形数字,也可以是无类型的指针(void*)常量,但是编译器默认情况下将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转(void *)0。 注意:
1. 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入的。

2. 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。

3. 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr。

  • 29
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小张正在路上

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

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

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

打赏作者

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

抵扣说明:

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

余额充值