C 无法创建将反转字符串的程序
我正在使用Linux。 我正在尝试用c语言编写一个程序,它将向后打印字符串。 这是我的密码:C 无法创建将反转字符串的程序,c,linux,string,invert,C,Linux,String,Invert,我正在使用Linux。 我正在尝试用c语言编写一个程序,它将向后打印字符串。 这是我的密码: #include <stdio.h> #include <string.h> #include <stdlib.h> int main (){ char string[100]; printf ("Enter string:\n"); gets (string); int length = strlen (string)-1;
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (){
char string[100];
printf ("Enter string:\n");
gets (string);
int length = strlen (string)-1;
for (length = length; length>=0; length--){
puts (string[length]);
}
}
我该怎么办?你应该使用
putchar
而不是put
所以这个循环:
for (length = length; length>=0; length--){
puts (string[length]);
}
将是:
for (length = length; length>=0; length--){
putchar (string[length]);
}
putchar
将单个字符作为参数,并将其打印到stdout
,这正是您想要的<另一方面,code>put会将整个字符串打印到stdout
。因此,当您将单个字符传递给需要整个字符串(字符数组,NULL终止字符串)的函数时,编译器会感到困惑。忘记函数gets()
存在-这是致命的。改用fgets()
(但请注意,它不会删除行尾的换行符)
您希望一次放置一个字符:使用putchar()
将其写入stdout。不要忘记在循环后向输出中添加换行符
另外,(length=length;length>=0;length--)的不是惯用的C。请使用以下选项之一:
- (;长度>=0;长度--)的
for(长度=strlen(字符串)-1;长度>=0;长度--)
for(int-length=strlen(string)-1;length>=0;length--)
最后一个替代使用了添加到C99的特征(以前在C++中是可用的)。
此外,我们还可以讨论
length
是否是变量的合适名称。最好将其重命名为i
或pos
或类似名称,因为尽管它初始化为输入的长度,但实际上它被用作数组索引,而不是任何内容的长度
主观:不要在函数名和参数列表之间留空格。C的开国元勋们不会这么做——你也不应该这么做
为什么它是致命的?
第一个互联网蠕虫——1988年的蠕虫——利用了fingerd
程序,该程序使用gets()
而不是fgets()
。从那时起,许多程序都崩溃了,因为它们使用的是get()
,而不是fgets()
或其他替代方法
基本问题是gets()
不知道有多少空间可用于存储它读取的数据。这会导致“缓冲区溢出”,这是一个可以在您喜爱的搜索引擎中搜索的术语,它将返回大量条目
如果有人向示例程序输入150个字符,那么get()
将在长度为100的数组中存储150个字符。这永远不会带来快乐-它通常会导致核心转储,但通过精心选择的输入(通常由Perl或Python脚本生成),您可能会让程序执行任意其他代码。如果程序将由具有“提升权限”的用户运行,这一点非常重要
顺便说一句,gets()
很可能在下一版本中从标准C库中删除(C1x-请参阅中的n1494)。它在很长一段时间内(20年?)不会从实际的C库中消失,但应该用这种实现(或类似的实现)来取代它:
#未定义NDEBUG
#包括
字符*获取(字符*缓冲区)
{
断言(“安全使用gets()的概率”==0);
}
另一个次要细节,在对主要问题的评论中部分讨论
显示的代码显然是针对C99的;在C89中,部分通过函数的length
声明无效。鉴于此,对于<代码>主()>代码>函数,它不显式返回值,因为C99标准遵循C++标准的领先,允许您省略从<代码>主()/代码>的返回,其效果与<代码>返回(0)相同;code>或返回0代码>在末尾
因此,这个问题中的程序不能因为结尾没有返回
而被严格地认为是错误的。然而,我认为这是一个更为特殊的标准化决策,如果标准遗漏了该条款,或者做了一些更激进的事情,比如允许普遍存在但错误的void main()
,注意到当控制权从中恢复时,结果是将成功状态返回到环境。令人遗憾的是,改变标准的这一方面是不值得的,但作为个人风格的决定,我不会利用许可证省略main()
中的最终返回值。如果代码必须与C89编译器一起工作,那么它应该有显式的返回0
在结尾(但是长度的声明也必须固定)。使用putc
或putchar
,因为put
被指定为获取char*
,并且您正在向它输入char,您也可以使用递归来完成此操作。我认为使用循环时看起来更好
只需使用字符串调用该方法,在方法中打印字符之前,使用相同的字符串(减去第一个字符)再次调用该方法
这将按相反的顺序打印字符串。首先:
从不使用get()
;它将在代码中引入一个故障点。无法判断目标缓冲区有多大,因此如果您传递一个大小为容纳10个字符的缓冲区,而输入流中有100个字符,get()
将很高兴地将这些额外的90个字符存储在缓冲区末尾以外的内存中,可能会破坏一些重要的内容。缓冲区溢出很容易被恶意软件利用;Morris蠕虫专门利用sendmail中的get()
调用进行攻击
改用fgets()
;它允许您指定从inp读取的最大字符数
for (length = length; length>=0; length--){
putchar (string[length]);
}
#undef NDEBUG
#include <assert.h>
char *gets(char *buffer)
{
assert("Probability of using gets() safely" == 0);
}
char string[100];
char *newline;
printf("Enter a string: ");
fflush(stdout);
fgets(string, sizeof string, stdin);
newline = strchr(buffer, '\n'); // search for the newline character
if (newline) // if it's present
*newline = 0; // set it to zero