c++中输入输出语句怎么写_stdout stderr

c++中输入输出语句怎么写_stdout stderrC++中的输入输出(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++中输入输出语句怎么写_stdout stderr分享到此就结束了,感谢您的阅读。

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

(0)
编程小号编程小号

相关推荐

发表回复

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