嵌入式笔记24 命名空间 输入和输出 C++对C的升级

本文深入讲解C++的关键特性,包括命名空间的使用及其注意事项、输入输出流的优化、C++相较于C语言的改进之处,如关键字升级、类型升级等,并探讨了内存管理的新方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


C++特点

封装、继承、多态

一、命名空间

命名冲突的解决

C语言中

1、c语言中解决命名冲突的方法:使用static关键字

  • 作用:
    修饰局部变量:延长局部变量的生命周期,程序结束后再释放
    修饰全局变量:该全局变量只能在本文件访问,不能在其他文件访问
    修饰函数:该函数只能在本文件调用,不能在其他文件调用
#include <iostream>

int count = 4;

int count = 5;
int main()
{
    return 0;
}

在这里插入图片描述
报错出现重复定义

C++中命名冲突的解决:命名空间

命名空间的定义

namespace 名字{变量、函数}

命名空间的使用

1、使用作用域限定符:使用命名空间的名字::变量名或者函数名
2、使用using关键字导入命名空间:using namespace 命名空间;using 命名空间::变量名或者函数名
eg:

#include <iostream>
namespace myspcaeA//解决命名冲突问题
{
     int count = 4;
     int index = 0;
}

namespace myspaceB
{ 
     int count = 5;
     int index = 10;
}
int count = 6;//默认全局的变量
int index = 20;
int main()
{
    printf("count = %d\n",count);//默认输出全局变量,输出6
    printf(“count = %d\n”,myspaceA::count);
    printf(“count = %d\n”,myspaceB::count);

    printf("count = %d\n",index);//默认输出全局变量,输出6
    printf(“count = %d\n”,myspaceA::index);
    printf(“count = %d\n”,myspaceB::index);
    return 0;
}

在这里插入图片描述

想要输出myspaceA里面的内容
引入运算符: ::作用域限定符

namespace myspaceB
{ 
     int count = 5;
     int index = 10;
     namespace myspaceBB//可以嵌套使用
     {
          int count = 7;
     }
     
}
 printf(“count = %d\n”,myspaceB::myspaceBB::count);//输出格式

//访问myspaceC中的数
namespace myspaceC
{
       int max = 10;
       int min = 10;
}

using namespace myspaceC;//将myspaceC导成全局变量
//using namespace myspaceA;
//using namespace myspaceB;//尽量少用using 导入命名空间,因为会导致命名冲突
//输出的话会再次出现命名冲突
printf("max = %d\n", max);//输出格式
以下情况

1、不同源文件可以有相同的命名空间
2、使用命名空间加作用域限定符访问成员时,优先导入本文件的命名空间
3、使用using导入命名空间时,导入的是所以程序中的命名空间(只要没有命名冲突都是被允许的)(直接导入)

防止头文件重复的两种方法

命名空间尽量定义在.h文件

//防止头文件重复包含的两种方法
//1、用宏
//2、#pragm once 预处理指令,z只编译一次(大部分使用)
//#ifndef __NAMESPACE_H_
//#define __NAMESPACE_H_//宏
#pragm once //预处理指令,z只编译一次
.
.
.
//#endif
std的介绍和使用
#include  <iostrenm>
//std:包含升级之后的功能
int main()
{ 
    std::cout << "hello world" << tsd::endl;
    //std:标准库命名空间
}
//简化
#include<iostream>
using namespace std;//此命名空间存放的是C++相对于C升级的功能(函数、库文件、变量)
int main()
{
    cout << "hello world" << endl;
}
命名空间注意事项

(1)不能访问其他源文件的命名空间
(2)当多个源文件的命名空间名字相同时:如果没有出现重复的变量名或者函数命名,系统会合并两个命名空间(但是实际上并不是合成一个命名空间,只是能通过编译);否则会报错

二、输入与输出

#include<iostream>

using namespace std;

int main()
{
    //cout printf 缓冲区
    const char *ptr = "hello world";

    char temp = 'X';

    int num = 6;

    double b = 1.342;

    cout << "hello world" << endl;

    cout << "ptr =" << ptr << endl;
    cout << "temp = " << temp << endl;

    cout << "num = " << num << endl;
    cout << "b = " << b << endl;

    cout << " &num = "<< &num << endl;

    printf("ptr = %p\n", ptr);


}

printf、cout缓冲区问题

printf

/*不能输出*/
#include <stdio.h>

int main()
{
    printf("hello world!");
    //scanf
    //flush;刷新缓冲区
    //while(1);也能输出,每次程序执行完后,清空缓冲区

    return 0;
}

printf:行缓冲:满一行输出或遇到‘\n’
使用printf调试时,一定要加’\n’或手动刷新缓冲区
scanf:输入前,刷新缓冲区

cout

#include <iostream>

using namespace std;

int main()
{
     cout << "hello worlld!" << endl;
     //  cout << "hello worlld!\n" 
     //endl相当于刷新,输入'\n'
     while(1)
        ;
     return 0;
}

cin输入

#include <iostream>

using namespace std;
int main()
{
     int num;
     char str[100];
     double b;
     //  //cin :输入流 cunt:输出流  cerr 错物流 clog 日志流 对象
     //流运算符:  >>输入  <<输出
     cout << "Please input num:";
     cin >> num;
     //getchar();
     cin.get();
     cout << "Please input str:";
     //cin >> str;
     cin.getline(str,100);
     //getline()
     cout << "Please input b:";
     cin >> b;
     
     cout << num << endl;
     cout << str << endl;
     cout << b << endl;
}

在这里插入图片描述
输入垃圾问题

缓冲区垃圾问题

getchar();
cin.get();

cerr错误流

#include <iostream>

using namespace std;
int main()
{
    cerr << "hello world!" << endl;//dup  dup2重定向到文件或某个远程socket里
    //cerr没有缓冲区
    clog << "hello world!" << endl;
    //clog有缓冲区

    return 0;
}

重定向

#include <stdio.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<unistd.h>

int main()
{
    //0标准输入 1标准输出 2标准出错
    int fd = open ("hello.txt", O_RDWR | O_CREAT, 0655);

    dup2(fd, STDOUT_FILENO);//输出重定向到fd上
    dup2(fd, STDIN_FILENO);//输入重定向    从文件里面读 
    dup2(fd, STDERR_FILENO);//错误信息重定向到fd

    //sockfd = socket confd;
    //dup2(STDOUT_FILENO,cond);

    char src[100];
    read(STDIN_FILENO, src, sizeof(src));//从键盘上读
    printf("src = %s\n",src);


    write(STDERR_FILENO, "hello world", 11);//输出到终端上

    return 0;

}
#include <iostream>
#include<stdio.h>
using namespace std;//标准库命名空间

int main()
{
    int num;
    char ch;
   
    //输入垃圾问题
    
    printf("Please input num:\n");
    scanf("%d",&num);
    getchar();

    printf("Please input ch:\n");
    scanf("%c",&ch);
     //cin :输入流 cunt:输出流  cerr 错物流 clog 日志流 对象
     //流运算符:  >>输入  <<输出
     cout << "hello world" << endl;
     cout << "num = " <<num<< endl;
     cout << "num = " << ch << endl;


    printf("num = %d  ch = %s\n",num,ch);
}

三、C++对C的升级

基本语句的升级

for语句

优化循环变量的作用域

#include <stdio.h>
int main()
{
int i;
for(i = 0; i<=100; i++{
}
//只有for循环结束后空间才能释放,浪费资源
return 0}
#include<iostream>

using namespace std;

int main()
{
    for(int i = 0; i < 100; i++) //节省空间,在C语言中也支持
    {

    }


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

    char src[100] = "hello world";

    for(char temp : src)
    {
        if(temp != '\0')
        {
            cout << temp << endl;
        }
        else
        {
            break;
        }
        
        
    }


    return 0;
}

条件表达式:可以做左值

关键字的升级register

程序的存储位置

在这里插入图片描述

C中register的使用

作用

提高程序运行效率(省去CPU从内存抓取数据的开销)

语法作用

尽可能将变量保存在CPU内部寄存器中

使用注意事项

1、只能修饰局部,不能修饰全局变量和函数
2、register修饰变量,不能通过&获取该变量的地址(有可能该变量保存在CPU内部寄存器中,&获取的是内存里的)
3、register修饰变量类型一定是CPU所能处理的数据类型(有的CPU不支持浮点型运算)

什么时候用register修饰一个变量

频繁访问的变量

volatile
作用

防止编译器优化(将变量优化到寄存器中(寄存器存在边际效应))

使用场景

访问硬件时,所使用的全局变量

volatile int count = 5volatile register int index;//提醒检查寄存器的变量是否有变化

C++中对register的升级

优化内容

当对register变量取地址时,会将该变量重新保存到内存中

#include<iosteram>

using namespace std;
int main()
{
     register int num = 5;
     printf("&num = %p\n",&num);
     return 0;
}

const关键字的升级:const修饰的是变量
地址之间的赋值必须是const对const
const:修饰变量、只读变量

const int num = 5const int *p_num = &num ;

关键字的升级auto

C语言中

自动变量,离开作用域时自动释放
只是用来说明该变量的作用域,相当于局部变量

C++中

auto变量:类型推导,实现高效编程

#include<iosteram>

using namespace std;
int main()
{
     int num = 5const char *ptr = "hello world";
     
     auto num1 = 5;//根据所赋值推导数据类型
     auto ptr1 = "hello world";

    int array[5] = {1,2,3,4,5} ;
    for(auto temp : array)
    { 
        cout << temp << endl;
    }
 
     vector<int> v = {1,2,3,4,5};
     //vector<int>::iterate it;
     for(auto it = v.begin(); it = v.end(); it++)
     {
          cout << *it << endl;
     }
     return 0;
}

auto ch1 = ‘a’;//
string s1 = “hello”;
string ::iterator it = s1.begin();
auto it2 = s1.begin();

关键字的升级typedef

C中typedef作用

typedef关键字的作用:给数据类型重命名

typedef工程应用作用

1、提高代码可读性
2、提高移植性

函数名命名规则

解决的是函数功能的可读性,无法解决形参的可读性

//提高代码的可读性
typedef int name_len;
int func(name_len a);//解释形参a的意思

typedef unsigned int Int;
Int num;
//想改int的类型

重命名:

pid_t pid;
size_t size;
mode_t mode;
off_t f;
typedef存在的问题

重命名函数指针时,可读性差

int add(int a,int b)
{
     return a+b;
}
int main()
{   
    typedef int (*P_FUNC)(int,int);
    //typedef int(*)(int,int) P_FUNC;
    int (*p_add)(int,int);//p_add函数指针变量
    P_FUNC p_add = add;//初始化
    p_add(5,6);//调用
    
    return 0;
}

C++中typedef的升级 typedef==using

using重命名
using关键的升级:替代C语言typedef的关键字

#include <iostream>
using namespace std;
int  add(int a,int b)
{
    return a+b;
}
int main()
{ 
        using P_FUNC = int (*)(int,int);
        using Int = int;
        Int aa = 5;
        P_FUNC p_add = add;
        cout << p_add(5,6) << endl;
        return 0;
}

using Int = int;//typedef int Int;
using Len = int;// typedef int Len;
using P_FUNC = int (*)(int,int);typedef

Int c;//int c;
Len c2;

add(6,5);
P_FUNC p_func;//int (*p_func)(int,int) = add;
p_func(6,5);

关键字const优化

C中const作用

将一个变量变为只读变量

什么是只读

在这里插入图片描述

const int num = 5int *p = & num;
*p = 7;
printf("num = %d\n",p);//还是会输出7,但是会报警告
int num = 5const int *p = & num;

int const *p = &num;//还是*p不可变
int * const p = &num;//是p不可变
*p = 7;
p++;//1
*p++;//2
num++;//3
//1、3可变

printf("num = %d\n",p);
工程应用的作用

修饰函数形参,保护实参在函数运行过程中不被改变

C++中const的升级

优化内容

const修饰的变量是常量

#include<iostream>
using namespace std;
int main()
{
int num = 5;
const int *p = &num;
cout << num << endl;
return 0;
}
constexpr

constexpr替换宏 #define

constexpr int getNum()
{
    return 5;
}
#define MAX(a,b) a>b?a:b //傻瓜式替换  无法定义复杂的函数(不检查语法错误)
constexpr int cout = 5;//相当于宏定义,检查语法错误
                       //这里count就是常数5,不可变   
cout++;//报错

C++对C的升级:类型的升级

引入bool类型

bool is_null = true;
bool is_null = flase;

三目运算符的升级

C语言中
int a = 5;
int b = 6;
(a>b?a:b) = 9;//报错,不可以这样赋值
C++语言中

1、结果可以作为左值

int a = 5;
int b = 6;
(a>b?a:b) = 9;//不报错,输出5,9
//while(a>b,a<b)支持,表达式

引用

C语言中
#include<stdio.h>
/*void swap(int a,int b)
{
     int temp;
     temp = a;
     a=b;
     b=temp;
}*/
void swap(int *a,int *b)
{
    int temp;
     temp = *a;
     *a=*b;
     *b=temp;
}
void func(char **ptr)
{
    (*ptr)++;
]
char * func2()//不要返回局部变量的地址或者指针
{
   static char src[100] = "heoll world";
   return src;
}
int main()
{
     int a =5;
     int b = 6;
     //swap( a,b);//实参变量名
     swap(&a,&b);
     //什么时候传地址,什么时候传值
     //当修改实参变量值时,传实参变量的地址(传实参变量的地址,既可以使用也可以修改实参变量的值)
     //当只使用不修改变量值时,传实参变量名(传实参变量名只能使用实参变量的值,不能修改)
     printf("a = %d,b = %d\n",a,b);
     char *ptr = "hello world";
     func(ptr);//传的是实参变量名
     func(&ptr);//实参变量地址
     printf("ptr = %s\n",ptr);
     char *result = func2();
     printf("result = %s\n",result);//返回result = (null)
     return 0;
}
C++语言中
引用作用

解决的是函数指针传参和返回值问题

语法作用

引用就是给变量起别名,操作引用相当于在操作引用所绑定的变量

#include<iostream>
using namespace std;
int main()
{
   int count = 5;
   int &r_count = count;
   r_count++;
   count++;
   cout << count << endl;//两者相互影响,改变其中一个,另一个也改变
   cout << r_count << endl;
}
注意事项

1、定义引用必须绑定变量(定义引用必须初始化,不能定义空引用)
2、一旦绑定就不能再次绑定到其他变量上

注:常引用:const修饰的引用,绑定常量

/*引用的作用:函数的形参和返回值*/
#include<iostream>
using namespace std;
void swap(int &a,int &b)//引用作为函数形参:传值和传地址问题
{
      int temp = a;
      a = b;
      b = temp;
      //实参和形参绑定
}
void test(const int &a)//a:常引用:只能使用不能修改其绑定的值
{
}

void & getNum(int a)//引用作为函数返回值
{
     static int temp = a + 1;
     return temp;
}
int main()
{
    int a = 5;
    int b = 6;
    swap(a,b);
    printf("a = %d b = %d\n",a,b);//两者交换
    getNum(a)  = 5;//函数调用做返回值:修改返回的值
    //getNum(a);输出结果为7
    cout << getNum(a) << endl;
}
作用场景

作为函数的形参,作为函数的返回值(函数的调用可以做左值)

int left = 5int right = 6;
swap(&left,*right);
count <<left << " "<< right;

void swap(int *left , int *right)
{
     int temp;
     temp = *left;
     *left = *right;
     *right = temp;
}

int temp = test();
test() = 10;//修改num的值

int left = 5;
int right = 6;

int &l_left = left;
cout << left << endl;

swap(&left,*right);
count <<left << " "<< right;

int const = 5;
int &
int func (const int &num1,const int num2)
{

}

void swap(int &left , int &right)
{
int temp;
temp = left;
*left = *right;
*right = temp;
}

int & test()
{
static int num = 5;
cout << num << endl;
return num;
}

引用是否占用额外的内存空间?

引用占用内存空间
编译器优化:不将这个空间展示给开发人员,不能操作这段空间“新的数据类型”

#include<iostream>
using namespace std;
struct node
{
    int n;
    int &rn;
};
int main()
{
   cout << sizeof(struct node) << endl;//输出占用16字节
}
左值、右值引用

C++11:左值引用、右值引用

左值

可以被修改的值可以作为左值(可以取地址的可以作为左值)

左值引用

只能绑定左值 int &

右值

不可以被修改的值可以作为右值(不可以取地址的可以作为右值)

右值引用

只能绑定右值 int &&(对象移动)

eg:判断左值还是右值
int num = 5;//num是左值,5是右值
int *p = &num;//&num是左值还是右值
(&num)++;//报错,不能加加,所以&num是右值
eg:引用
void func1(int &l_num)//左值引用作形参
{
     cout << l_num << endl;
}
void func2(int &&r_num)
{
     cout << r_num << endl;
}
int main()
{
int num = 5int &l_num = num;
int &&r_num = 5;//移动构造函数,移动拷贝赋值运算符的重载
r_num++;//不报错,所有它是2左值
//int &&r_num1 = r_num;//报错
func1(num);
func1(l_num);//l_num++
//func1(5);//报错,单纯的左值引用不可以绑定常量
//上面函数改成  void func1(const int &l_num){}就可以
func2(5);
//func2(r_num);//报错,左对左,右对右,r_num是个左值
func2(std::move(r_num));//将左值转换成右值
func1(r_num);
return 0;
}
左值转换成右值
std::move();
eg
func2(std::move(r_num));//将左值转换成右值

作业
引用是不是数据类型?(不是)它占不占用内存空间(运行时不占用内存空间, 编辑时预留内存空间!!!!
指针和引用的区别
什么是对象移动?对象移动的作用?

malloc/free升级,引入new、delete

malloc、free
#include<stdio.h>
#include<stdlib.h>
int main()
{
     //void * malloc(size_t size);分配的空间大小
     //void free(void *adrr);释放的空间地址
     char *ptr = (char *)malloc(sizeof(char) * 100);//指针赋值一定是相同类型
     int *p_arr = (int *)malloc(sizeof(char) * 100);//400字节(4*100)按字节分配
     if(ptr == NULL)
     {
          perror("malloc error!");
          exit(1);
     }

     memset(ptr,0,sizeof(char) * 100);//设初值
     strcpy(ptr,"hello world!");//拷贝字符串
     free(ptr);//free函数如何知道要释放多少内存空间?
     ptr = NULL;
     return 0;
}
new、delete
#include<iostream>
using namespace std;

int main()
{
    /*分配的同时初始化*/
    char *p = new char('a');//分配一个字节
    cout << *p << endl;//输出a
    //按类型个数分配
    char *ptr = new char[100];
    delete p;//释放
    delete [] ptr;
    //  char *ptr = new char[100]{"hello world"};不支持
    //int *p_arr = new int[10]{1,2,3,4};//支持
    /*for(i=0;i<10;i++)
    {
         cout << p_arr[i] << endl;//没有输出
    }*/
    //分配二维数组
    int (*p)[5]=new int[4][5];
    char (*ptr)[100] = new char[3][100];
    
    int **array2;//适合分配不规则的多维数组
    array2 = new int *[2];
    for(int i = 0;i<2;i++)
    {
         array2[i]=new int[3];
    }
    //分配三维数组

    int (*p)[2][100] = new  int[3][2][100];
    return 0;
}
malloc free vs new delete

1、new、delete(暂时)理解为运算符 malloc、free是函数
2、new、delete按照类型的个数为单位 malloc、free按照字节为单位分配
3、new、delete:可以初始化 malloc、free只能手动初始化
(关于初始化:最好手动初始化 默认初始化都是0)
4、new、delete:如果分配失败会产生异常, malloc、free:返回NULL
5、new底层调用的是malloc delete底层调用还是free
6、new、delete:频繁分配小内存会导致内存产生碎片,同时会增加开销(系统) 池化技术:内存池

关于多维数组的分配
规则多维数组
int (*p)[3]=new int [3][3]
不规则的多维数组
int **array;

NULL升级

NULL: #define NULL (void *)0//0地址
C++中nullptr
char *ptr = nullptr;

函数的升级

C++对C的升级:函数的升级
引入inline关键字修饰函数:用(内存)空间换运行时间
引入默认参数:可以给形参设定默认参数 规则默认参数的右边参数必须全为默认参数
可以函数重载:可以使用相同的函数名 重载规则:形参的个数、类型或者顺序不同
注意事项:函数返回值不能作为重载条件,默认参数会影响重载规则

int add(int a,int b)
{

}
int add (int a,int b,int c)//个数不同
{
}
int add(char a, char b)
{
}
int add(int a,string b,int )//参数占位
{
}

add(6,5);
add(6,5);
add(6,5);

inline int add(int a, int b)//内联函数
{
return a+b;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

qq_49181551

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

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

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

打赏作者

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

抵扣说明:

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

余额充值