无法创建一个会反转字符串的程序

时间:2010-09-02 13:33:03

标签: 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;
    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.

我该怎么办?

5 个答案:

答案 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是否是变量的适当名称。最好将其重命名为ipos或类似的东西,因为尽管它初始化为输入的长度,但它实际上用作数组索引,而不是任何长度。< / p>

主观:不要在函数名称和参数列表之间放置空格。 C的创始人不这样做 - 你也不应该这样做。


为什么gets()致命?

第一个互联网蠕虫 - 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)

使用putcputchar,因为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()