大家好,关于scanf为什么不安全很多朋友都还不太明白,不过没关系,因为今天小编就来为大家分享关于scanf为什么不建议用的知识点,相信应该可以解决大家的一些困惑和问题,如果碰巧可以解决您的问题,还望关注下本站哦,希望对各位有所帮助!
本文目录
scanf为什么不安全
`scanf`函数被认为不安全的主要原因是因为它在接受用户输入时没有提供足够的安全性保障。
由于`scanf`需要用户提供变量的地址作为参数来存储输入数据,用户可以通过恶意输入或错误输入导致缓冲区溢出和未定义行为。这可能导致程序崩溃、数据损坏或安全漏洞。为了确保安全的输入处理,推荐使用更安全的输入函数(如`fgets`)结合适当的输入验证和错误处理机制来代替`scanf`。
请问c语言中,int类型变量所占字节数是
编译器可以根据自身硬件来选择合适的大小,但是需要满足约束:short和int型至少为16位,long型至少为32位,并且short型长度不能超过int型,而int型不能超过long型。这即是说各个类型的变量长度是由编译器来决定的,而当前主流的编译器中一般是32位机器和64位机器中int型都是4个字节(例如,GCC)。
数据类型占内存的位数实际上与操作系统的位数和编译器(不同编译器支持的位数可能有所不同)都有关
,具体某种数据类型占字节数得编译器根据操作系统位数两者之间进行协调好后分配内存大小。具体在使用的时候如想知道具体占内存的位数通过sizeof(int)可以得到准确的答案。对于0来说,它的原码和反码都有两种(分别为00000000,10000000,和00000000,11111111),但是补码只有一种(即00000000),-0的补码形式等于对应的正数0的原码00000000,取反为11111111,加1是00000000,答案仍然是0,溢出了。整数0,小数0的补码都只有这一种形式。同时也是说,补码没有10000000这个值(用来干啥好呢?所以就赋给-128.。。。),其实不是的,-127的原,反,补为:1111?1111,?1000?0000,?1000?0001,因为穷举法,补码?1000?0000?为?-128?是不用怀疑的,所以,8位有符号的整数取值范围的补码表示10000000到00000000,再到01111111即-128到0,再到127最终-128~+127,中间没有中断,一直是往上加1的,只不过到0的时候溢出了。-128没有原码,也没有反码,都被-0占了(分别是10000000和11111111)。
一个二进制数的补码的补码就是原码!!!(2019/3/27补充一下,一个正数的补码的补码是它相对应的负数的补码,同理,一个负数的补码的补码是它相对应的正数的补码,也就是说,一个正数的原码就是它相对应的负数的补码,懂了没?)
枚举类型enum的元素长度根据编译器而定。在visualc++下,它和int一样长,是4个字节,在GCC下它会取尽可能短的长度,例如你这个枚举类型只有3种标识,那么它是一个字节。
12的平方是int在GCC中的极限平方了,到了13的平方就会溢出,int型数组建立20万个没事,建立100万个就创建不出了,因此在数组建立不出来时,尽量让数组放在函数之外,因为如果数组太大,放在函数内有可能会崩溃,在函数之外则不会有这样的问题。因为在函数外定义属于全局变量,全局变量在静态存储区分配内存,而局部变量是在栈上分配内存空间的,如果数组太大,可能会造成栈溢出。
使用static_cast可以找回存放在void指针中的值。一般用于malloc,它的返回值正是void,这叫自带解释。。double*dptr=static_cast<double*>(vptr);
C11增加了一些新特性,and,or,not何以取代&&||!真方便!
for(expression:struct)完全也可以用普通数组这个语法糖,但是指针就不行,而且是值传递的,也就是不能修改。
括号失效:有时你明明以为加了括号可以保证万无一失,但是还是可能跑偏了,例如intc=++b*(a+b)因为有那个自增的运算符,整个表达式异常凶险。。。
要注意int的有无符号的问题,如果不注意的话,得出的结果会非常奇怪,例如:intx=2;char*str="abcd";inty=(x-strlen(str))/2;printf("%d\n",y);结果应该是-1但是却得到:2147483647。为什么?因为strlen的返回值类型是size_t,也就是unsignedint,与int混合计算时,int类型被自动转换为unsignedint了,结果自然出乎意料。。。解决办法就是强制转换,变成inty=(int)(x-strlen(str))/2;强制向有符号方向转换(编译器默认正好相反),所以牵扯到有符号无符号计算的问题,特别是存在讨厌的自动转换时,要倍加小心!(这里自动转换时,无论gcc还是cl都不提示!!!)为了避免这些错误,建议,凡是在运算的时候,确保你的变量都是signed的。
c编译器中,仅支持C89规范的编译器,只支持在作用域起始部分(大括号最开始)定义变量。支持C99或者部分支持C99的编译器,局部变量可以定义在任何位置。基本上绝大多数都支持了,甚至还有一部分支持for(inti),但是并不建议在C语言中用这个。
早在C++98标准中就存在了auto关键字,那时的auto用于声明变量为自动变量,自动变量意为拥有自动的生命期,这是多余的,因为就算不使用auto声明,变量依旧拥有自动的生命期,C++98中的auto多余且极少使用,C++11已经删除了这一用法,取而代之的是全新的auto:变量的自动类型推断。auto可以在声明变量的时候根据变量初始值的类型自动为此变量选择匹配的类型。
有时候不引用string头文件仍然可以使用string,那是因为有可能某一个头文件里包括了它自己的,不同平台可能有不同,在这里不要偷懒。
map的值是按照key升序排列的,也就是说,自动排列。
对于输入输出,在最后输出回车还是空格的问题上,聪明人都用三目元表达式(i==n-1)?"\n":"",但是注意要把表达式全部用括号括起来,为了防止编译器分析不当,而且这种情况时有发生。
如何在类似for(autovar:set){}这种语句里确定var到底是不是最后一个?或者说set怎么确定其中的值是最后一个?这里有讲究:var==*(--set.end())注意是自减而不是-1,--是重载了的,而-没有重载,所以会报错的,而且注意是前面自减才对。
要用<iostream>而不要用<iostream.h>,后者只是仅仅支持字符流,而前者包含了一系列模板化的I/O类,二者在接口和执行上都是不同的。
scanf函数的返回值反映的是按照指定的格式符正确读入的数据的个数。也就是说,可以运用while(scanf(“%d”,&x)==1){}来更加简化没有确定数据个数时的代码段,那么,这里只能输入字母来结束输入,在scanf中,回车,空格,tab键是无关紧要的,也就是输入多少也不会管,只有按下空格,再按Ctrl+z,然后再按回车,才算结束输入,这时候scanf接受的是第一个空格之前的字符,在Linux中,按下回车,再按下Ctrl+D即可结束输入,也就是说,scanf的这种特性基本没用,只有在ACM中有用。scanf的返回值用在什么地方呢?用在没有给出有多少数据,一次性输入完就算的那种,这么写:while(scanf("%d%d",&m,&n)!=EOF){}感觉还方便.
gets在C++中会产生bug,而且在C11标准中被废除,因此不建议使用,getline(cin,str)函数只能读取string类型,不能读取字符数组类型,cin.get可以读取字符数组类型,并且只会遇到回车而结束。用法为cin.get(ch,长度),另外需要注意的是,这个函数会将换行符留在输入队列中,如果连续两次调用,第二次将无法读入,应加上一个不带参数的cin.get吃掉换行符,推荐用cin.ignore(),因为看起来自带注释的感觉,另外cin>>noskipws也有读取空格字符串的功能。一般的,常会有使用一次cin之后连续多次使用getline,但是,由于cin不读入空格的特性,getline总会少输入一行,所以正确姿势是用cin.get()或者cin.ingnore(),感觉用后者更自带注释一些。
"\n"表示内容为一个回车符的字符串。std::endl是流操作子,输出的作用和输出“\n”类似,但可能略有区别。std::endl输出一个换行符,并立即刷新缓冲区,由于流操作符<<的重载,对于‘\n’和“\n”,输出效果相同。对于有输出缓冲的流(例如cout、clog),如果不手动进行缓冲区刷新操作,将在缓冲区满后自动刷新输出。不过对于cout来说(相对于文件输出流等),缓冲一般体现得并不明显。但是必要情况下使用endl代替‘\n’一般是个好习惯。对于无缓冲的流(例如标准错误输出流cerr),刷新是不必要的,可以直接使用‘\n’。
fgets(buff,MAXN,fin)将读取完整的一行存放到buff字符数组中,而且往往是以\n结尾(除了在文件结束前没有遇到\n这种特殊情况)。当一个字符也没有读到,函数返回null。同样有一个标准输入板的gets(s)函数,里面只有一个数组参数,风险较大,不建议使用。而在scanf中,是不包括\n的,但是也不能在接受字符串中打上\n,回车是一个输入完成键,在scanf与fgets混用时(我为什么要混用?可能以后再也不会混用了)要注意这个点。
对于上下左右和别的一些扩展键使用getch会先返回一个224,再使用一次getch()这时返回的才是扫描码。
关于memset,只用它来初始化0就行了,初始化其他的,全错!相信我,memset函数也是以字节为单位进行赋值的,对于int型,是四个字节,也就是将这四个字节设置成0x01010101,转换成十进制就是16843009。memset的作用是来将一段内存按自己进行初始化,并非用来进行变量初始化。
值得注意的是,c++的结构体是可以有构造函数的,这也可以说,如果构造一个链表结构体的话,那么就非常有用了是不是,在销毁的时候顺便释放空间什么的,结构体中可以包含函数;也可以定义public、private、protected数据成员,结构体定义中默认情况下的成员是public,而类定义中的默认情况下的成员是private的。类中的非static成员函数有this指针,(而struct中没有是错误的,一直被误导啊,经过测试struct的成员函数一样具有this指针),类的关键字class能作为template模板的关键字即template<classT>classA{};而struct不可以。
C++中定义结构体变量时可以不加struct关键字,也就是说,typedef可以在c++中省掉了。
不建议使用全局对象,因为debug只能从main处进入,而类的初始化在main开始之前,所以根本没办法调试。另外,由于全局变量创建顺序完全不可控,更不要让全局变量之间相互依赖。
额,就先这么多吧。。
vs中scanf报错怎么解决
1.方法一:(我推荐使用这种方法)
首先找到你安装VS的路径然后按下面路径找到E:\VS2019\Common7\IDE\VC\VCProjectItems文件夹
?
在里面找到newc++file.cpp这个文件,然后将这个文件复制到桌面上用vs打开,然后将#define_CRT_SECURE_NO_WARNINGS1复制到里面,保存退出,最后将桌面上的文件转移到原路径下,并替换掉源文件,这样就好了,并且在以后创建.c文件时,系统都会默认添加这行代码在你的.c文件里,以后就不会出现问题了
2.方法二:
找到你创建的项目,右击找到属性,找到c/c±---->常规---->SDL检查,将是改为否最后点击确定就行了。不够这种方法在每次创建新项目是都要设置一下,比较麻烦,所以还是推荐使用方法一,设置一次后以后创建新文件都不用设置了。
算法竞赛的时候,用cin cout输入输出比用scanf printf慢多少
应@真正的力子的邀请,来回答这个问题,看了一下这个问题,让我想起了我大一,刚刚跨入大学的时候,遇到的第一个ACM的编程题目,先把题目贴一下:
很简单,就是两个数相加,输出加的结果。我们先来测试一下两段代码的性能,再来分析慢还是快,为什么用cin在写上面这个问题的时候,总是TimeOut,而必须使用while(scanf("%s%s",&a,&b)!=EOF){}才行。a.cpp用C++写的一个代码,很简单,如下所示:
b.cpp,用C语言写的一个实现同样功能的代码,如下所示:
OK,我们伪造1亿条数据取测试一下,看看代码的性能如何,经过测试,我的机器配置如下
Linux4.9.0-0.bpo.3-amd64#1SMPDebian4.9.30-2+deb9u5~bpo8+1(2017-09-28)x86_64GNU/Linuxscanf和printf组合运行的时间是33秒,而cin和cout的运行时间是230秒。可想而知,性能差距是多大啊。
一般来说,在ACM比赛中,我们都会建议用scanf,而不用cin,因为cin是C++编程语言中的标准输入流对象,即istream类的对象。cin主要用于从标准输入读取数据,这里的标准输入,指的是终端的键盘。
OK,关于scanf为什么不安全和scanf为什么不建议用的内容到此结束了,希望对大家有所帮助。
声明:本文内容来自互联网不代表本站观点,转载请注明出处:https://bk.77788889.com/12/107931.html