c++中输入输出语句怎么写_const指针赋值给非const

c++中输入输出语句怎么写_const指针赋值给非constC++中的输入输出(stdin,stdout和stderr)const与指针、const与引用相关问题_stderr

1. stdin,stdout和stderr的理解

Linux系统下,当一个用户进程被创建时,与之对应的三个数据流(stdin,stdout和stderr,即三个文件)也会被创建。

  • stdin,标准输入文件,通常对应着终端的键盘。
  • stdout,标准输出文件,通常对应着终端的屏幕。
  • stderr,标准错误输出文件,通常对应着终端的屏幕。
    默认情况下,三个数据流对应的文件描述符分别是stdin—0,stdout—1,stderr—2,可通过如下代码查看。
#include <iostream> #include <cstdio> int main() { 
    int stdinFd = fileno(stdin); int stdoutFd = fileno(stdout); int stderrFd = fileno(stderr); std::cout << "stdinFd: " << stdinFd << std::endl; std::cout << "stdoutFd: " << stdoutFd << std::endl; std::cout << "stderrFd: " << stderrFd << std::endl; return 0; } 

值得注意的是,stdout和stderr存在着一个重要的区别。
程序如下(Linux环境下运行)

#include <stdio.h> int main(){ 
    fprintf(stdout, "hello"); fprintf(stderr, "world"); return 0; } 

程序输出结果如下

worldhello 

原因在于,stdout存在一个缓冲区,它的输出会先放在缓冲区里面,遇到换行或者缓冲区刷新时才会输出到屏幕上。而stderr不存在缓冲区,也就是说stderr的输出内容会直接打印在屏幕上。所以会出现上面的输出结果。

2. C++的统一初始化和输入输出

C++统一初始化——列表初始化 { }

#include <iostream> using namespace std; struct example{ 
    char str[10]; int n; }; int main(){ 
    //普通变量初始化,下面六条语句作用相同 int a1 = 10; int a2(10); int a3 = int(10); int a4 = { 
   10}; int a5 = int{ 
   10}; int a5{ 
   10}; //数组初始化,下面两条语句作用相同 int arr[5] = { 
   1,2,3,4,5}; int arr1[5]{ 
   1,2,3,4,5}; //结构体初始化 struct example exa { 
   "hello", 3}; return 0; } 

从上面程序可以看出,变量都可以使用花括号{ }进行初始化,所以{ }成为C++的一种统一初始化方式。需要注意的是,列表初始化具有更强的类型检查,如下。

#include <iostream> using namespace std; int main(){ 
    double a = 1.2; int b = a; //代码正常运行,b == 1 int c = { 
   a}; //代码报错(从"double"转换到"int"需要收缩转换) int d = { 
   (int)a} //代码正常运行 return 0; } 

C语言的输入输出最常见的是scanf 和 printf,这里需要注意的是,scanf是不安全的,自从Visual Studio 2005开始,scanf被scanf_s取代,在调用scanf_s时必须额外提供一个参数以表明最多读取多少位字符,代码如下。

#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main(){ 
    char str[5]; scanf("%s", str); printf("%s\n", str); return 0; } 

程序的输入输出为

helloworld helloworld 

调试代码,查看变量str
在这里插入图片描述

从调试结果可以看出,从str[4]之后(str[4]本身应该是’\0’),内存空间被非法写入,这可能引起别的变量被修改或者导致程序异常。为了避免这个问题,VS提供了scanf_s,上面程序的输入语句修改如下

scanf_s("%s", str, 5); 

其中,5表示str的容量,由于字符串最后一位要设置为’\0’,所以str最大可读入4个字符。程序的输入输出如下。

//输入 hell //输出 hell 

在这里插入图片描述

这里需要注意的是,对函数scanf_s来说,当输入的数据超出变量的大小时并不是采取截断的方式,而是直接置为”\0″。意思就是,当输入数据为”helloworld”时,str并不是存储了”hell”,将”oworld”丢弃,而是直接将str置为空,str[0]置为了”\0″。如下
在这里插入图片描述

C++语言的输入输出使用的是cin和cout,必须包含头文件<iostream>和std标准命名空间,如下。

#include <iostream> using namespace std; int main() { 
    const int n = 5; char str[n]; cin >> str; cout << str << endl; return 0; } 

cin的输入是以空格、换行或者制表符作为分隔符,如下。

#include <iostream> using namespace std; int main() { 
    const int n = 12; char str[n]; cin >> str; cout << str << endl; return 0; } 

当输入为”hello world”时,str只会接收”hello”,而将” world”留给下一个变量接收。

//输入 hello world //输出 hello 

如果想把空格输入到字符数组str中去,可以使用getline函数。

#include <iostream> using namespace std; int main() { 
    const int n = 12; char str[n]; cin.getline(str, n); cout << str << endl; return 0; } 

程序输入输出如下

//输入 hello world //输出 hello world 

如果想把空格和换行都输入进去,需要额外再给getline提供一个终止符。

cin.getline(str, n, '#'); 

程序输入输出如下

//输入 hell o wor # //输出 hell o wor 

从下面的调试结果可以看出,空格’ ‘和换行’\n’都已经被输入进去。
在这里插入图片描述

3. const在C和C++中的不同之处

const在C和C++中,对常变量的处理方式不同(编译阶段,C中以变量为主,C++中以常量为主),以一段最简单的代码来看。

#include <stdio.h> int main(){ 
    const int n = 10; int arr[n] = { 
   1,2,3,4,5}; return 0; } 

上面这个代码,如果运行在.c文件中会报错,而在.cpp文件中确能正常运行,这只是简单的展示了C和C++确实对const有着不同的处理方式,下面从汇编角度分析为何会出现这种情况。代码如下。

#include <stdio.h> int main(){ 
    const int a = 10; int b = 0; int *p = (int*)&a; *p = 100; b = a; printf("a=%d *p=%d b=%d\n", a, *p, b); return 0; } 

如果将上面的代码运行在.c文件中,程序输出结果如下。

a=100 *p=100 b=100 

这似乎不值得惊讶,通过分析代码很容易得出这个结论。但如果将这段代码运行在.cpp文件中,输出结果可能令人不那么容易理解,如下。

a=10 *p=100 b=10 

在VS2019中,通过对代码进行调试并进行反汇编来查看编译阶段C和C++对const的不同处理,进一步理解这个过程。首先来看.c文件下的调试和汇编。
在这里插入图片描述

再来看.cpp文件下的调试和汇编。
在这里插入图片描述

对比之下可以发现,在cpp文件中,从汇编的角度上看,常变量a出现的地方被10替换了,换句话说就是每当常变量a(单独)出现的地方直接被替换成了10,从代码上理解就是

b = a; //被替换成了 b = 10; printf("a=%d *p=%d b=%d\n", a, *p, b); //被替换成了 printf("a=%d *p=%d b=%d\n", 10, *p, b); //当然这条语句中的a是无法进行替换的,也就是上面为什么强调单独出现 int *p = (int*)&a; 

这就是const在C和C++中的不同之处,C中以变量为主,C++中以常量为主。

4. const与指针

能力强的指针赋值给能力收缩的指针,该操作是正常的。
能力收缩的指针赋值给能力强的指针,该操作是错误的。

#include <iostream> usi int main() { 
    int a = 10; const int *p = &a; //right int *s1 = p; //error const int *s2 = p; //right int * const s3 = p; //error const int * const s4 = p; //right return 0; } 
#include <stdio.h> int main() { 
    int a = 10; int * const p = &a; //right int *s1 = p; //right,通过s1并不能修改p const int *s2 = p; //right int * const s3 = p; //right const int * const s4 = p; //right return 0; } 

5. const与引用&

引用的定义:类型& 引用变量 = 变量;

#include <stdio.h> int main() { 
    int a = 10; int &b = a; //引用 return 0; } 

const引用

#include <iostream> using namespace std; int main() { 
    int a = 10; const int b = 20; int& x = a; //right int& y = b; //error const int& x1 = a; //right const int& y1 = b; //right int& x2 = 10; //error int& y2 = 20; //error const int& x3 = 10; //right const int& y3 = 20; //right return 0; } 

引用作为参数取代指针(传址)

#include <iostream> #include <cassert> using namespace std; void swap_point(int* p1, int* p2) { 
    assert(p1 != NULL & p2 != NULL); int tmp = *p1; *p1 = *p2; *p2 = tmp; } void swap_refer(int& num1, int& num2) { 
    int tmp = num1; num1 = num2; num2 = tmp; } int main() { 
    int a = 10, b = 20; cout << "a = " << a << " b = " << b << endl; swap_point(&a, &b); cout << "a = " << a << " b = " << b << endl; swap_refer(a, b); cout << "a = " << a << " b = " << b << endl; return 0; } 

从上面的代码来看,引用提供了一种更加简单的方式实现传址
引用数组和指针

#include <iostream> using namespace std; int main() { 
    int a = 10; int arr[3] = { 
    1,2,3 }; int* p = &a; int*& r = p; //引用指针 int& b = arr[0]; //引用数组元素 int(&parr)[3] = arr;//引用数组 return 0; } 

在这里插入图片描述

引用和指针的区别总结

  1. 语法规则上看,指针存储某个变量的地址,而引用是某个变量的别名;
  2. 指针变量需要分配内存区域,而引用不需要;
  3. 解引用时指针前面要加上*,而引用可以直接使用;
  4. 指针变量的值可以改变,存储不同变量的地址,而引用在定义时就被初始化,之后无法改变;
  5. 指针变量的值可以为空(NULL或nullptr),却没有空引用;
  6. 指针变量作为形参时需要检查它的合法性(判空),而引用不需要判空;
  7. 对指针变量使用”sizeof”得到的是指针变量的大小,而对引用使用”sizeof”得到的是变量的大小;
  8. 理论上指针的级数没有限制,但引用只有一级,不存在引用的引用,但可以有指针的指针;
  9. ++指针和++引用效果不一样;

从汇编角度上理解引用和指针的区别,代码如下。

#include <iostream> using namespace std; int main() { 
    int a = 10; int* p = &a; int& b = a; *p = 20; b = 30; return 0; } 

在这里插入图片描述

从上图可以看出,在汇编层面对引用的操作和对指针的操作是一样的。其实引用本身就是利用指针来实现的,&和*const的作用相同。

今天的文章
c++中输入输出语句怎么写_const指针赋值给非const分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/80878.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注