我正在使用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;
for (length = length; length>=0; length--){
puts (string[length]);
}
}
这是错误:
a.c:10: warning: passing argument 1 of ‘puts’ makes pointer from integer without a cast
/usr/include/stdio.h:668: note: expected ‘const char *’ but argument is of type ‘char’
/tmp/cc5rpeG7.o: In function `main':
a.c:(.text+0x29): warning: the `gets' function is dangerous and should not be used.
我该怎么办?
答案 0 :(得分:11)
忘记函数gets()
存在 - 它是致命的。请改用fgets()
(但请注意,它不会删除行尾的换行符。)
您希望一次放置一个字符:使用putchar()
将其写入stdout。不要忘记在循环后向输出添加换行符。
此外,for (length = length; length >= 0; length--)
不是惯用的C.使用以下之一:
for ( ; length >= 0; length--)
for (length = strlen(string) - 1; length >= 0; length--)
for (int length = strlen(string) - 1; length >= 0; length--)
最后一种方法使用添加到C99的功能(很久以前就可以在C ++中使用)。
另外,我们可以讨论length
是否是变量的适当名称。最好将其重命名为i
或pos
或类似的东西,因为尽管它初始化为输入的长度,但它实际上用作数组索引,而不是任何长度。< / p>
主观:不要在函数名称和参数列表之间放置空格。 C的创始人不这样做 - 你也不应该这样做。
第一个互联网蠕虫 - 1988年的Morris蠕虫 - 利用了使用fingerd
代替gets()
的{{1}}程序。从那时起,许多程序都因为使用fgets()
而不是gets()
或其他替代方案而崩溃。
基本问题是fgets()
不知道有多少空间可用于存储它读取的数据。这会导致“缓冲区溢出”,这个术语可以在您最喜欢的搜索引擎中搜索,该搜索引擎将返回大量条目。
如果某人输入了150个字符的输入到示例程序,那么gets()
将在数组中存储150个字符,其长度为100.这永远不会带来快乐 - 它通常会导致核心转储,但要谨慎选择的输入 - 通常由Perl或Python脚本生成 - 您可以使程序执行任意其他代码。如果程序将由具有“提升权限”的用户运行,这真的很重要。
顺便提一下,gets()
可能会在下一版本中从标准C库中删除(C1x - 请参阅WG14中的n1494)。它不会在很长一段时间内(20年?)从实际的C库中消失,但它应该被这个实现(或类似的东西)取代:
gets()
另一个小细节,部分在主要问题的评论中讨论。
显示的代码显然是C99;通过该功能的#undef NDEBUG
#include <assert.h>
char *gets(char *buffer)
{
assert("Probability of using gets() safely" == 0);
}
声明在C89中无效。鉴于此,length
函数没有显式返回值是'OK',因为C99标准遵循C ++标准的引导并允许您省略main()
的返回和效果最后与main()
或return(0);
相同。
因此,在最后没有return 0;
的情况下,此问题中的程序不能严重失误。然而,我认为这是一个比较特殊的标准化决策,并且如果标准将该条款排除在外,则会更喜欢它 - 或者做一些更激进的事情,例如允许无处不在但错误的return
观察当控制从结果是成功状态返回到环境。遗憾的是,改变标准的这一方面是不值得的 - 但作为一种个人风格决定,我没有利用授予的许可从void main()
中省略最终的return
。如果代码必须与C89编译器一起使用,那么它最后应该有明确的main()
(但是return 0;
的声明也必须修复。)
答案 1 :(得分:1)
您也可以使用递归来完成它。我觉得它在使用循环时看起来更好。
只需使用您的字符串调用该方法,然后在方法中打印char之前,再次使用相同的字符串调用该方法,减去第一个字符。
这将以相反的顺序打印出你的字符串。
答案 2 :(得分:0)
您应该使用putchar
代替puts
所以这个循环:
for (length = length; length>=0; length--){
puts (string[length]);
}
将是:
for (length = length; length>=0; length--){
putchar (string[length]);
}
putchar
将单个字符作为参数并将其打印到stdout
,这就是您想要的。另一方面,puts
会将整个字符串打印到stdout
。因此,当您将一个char传递给期望整个字符串(char数组, NULL 终止字符串)的函数时,编译器会感到困惑。
答案 3 :(得分:0)
使用putc
或putchar
,因为puts
被指定为char*
而你正在为它char
提供。
答案 4 :(得分:0)
首先:
绝不永远不会使用gets()
; 将在您的代码中引入一个失败点。没有办法告诉gets()
目标缓冲区有多大,所以如果你传递一个大小为10个字符的缓冲区并且输入流中有100个字符,gets()
将很乐意存储这些额外的90个字符。超出缓冲区末尾的内存,可能会破坏重要的东西。缓冲区溢出是一种容易被恶意软件利用的漏洞; Morris蠕虫专门利用sendmail中的gets()
电话。
改用fgets()
;它允许您指定从输入流中读取的最大字符数。但是,与gets()
不同,fgets()
会将终止换行符保存到缓冲区(如果有空间),因此您必须考虑到这一点:
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
现在已经不在了......
您的错误来自于puts()
期望类型为char *
的参数,但您传递的类型为char
的参数,因此“没有强制转换的整数指针“消息(char
是一个整体类型)。要将单个字符写入stdout,请使用putchar()
或fputc()
。