我正在使用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.

我应该怎么办?

有帮助吗?

解决方案

第一的:

永远不会从不 利用 gets();它 将要 在您的代码中引入故障点。没有办法告诉 gets() 目标缓冲区有多大,因此,如果您通过缓冲区大小以保持10个字符,并且输入流中有100个字符,则 gets() 将在缓冲区末端的内存中快乐地存储这些额外的90个字符,并有可能抓住重要的东西。缓冲区超支是一种简单的恶意软件利用;莫里斯蠕虫专门利用 gets() 致电Sendmail。

利用 fgets() 反而;它允许您指定从输入流读取的最大字符数。但是,与众不同 gets(), fgets() 如果有空间,将将终止的newline字符保存到缓冲区,因此您必须考虑到:

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().

其他提示

忘记功能 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 或类似的东西,因为它被初始化为输入的长度,但实际上被用作数组索引,而不是任何内容的长度。

主观: :不要在函数的名称及其参数列表之间放置空间。 C的开国元勋不这样做 - 您也不应该这样做。


为什么get()致命?

第一个互联网蠕虫 - 莫里斯 1988年的蠕虫 - 利用 fingerd 使用的程序 gets() 代替 fgets(). 。从那以后,许多程序崩溃了,因为他们使用了 gets() 并不是 fgets() 或其他选择。

基本问题是 gets() 不知道有多少空间可用于存储其读取的数据。这导致“缓冲区溢出”,该术语可以在您喜欢的搜索引擎中搜索,该术语将返回大量条目。

如果某人键入示例程序的150个字符的输入,则 gets() 将在数组中存储150个字符的长度为100。这永远不会带来幸福 - 通常会导致核心转储,但是经过精心选择的输入(通常由Perl或Python脚本生成),您可能可以使程序可以执行任意任意其他代码。该程序是否会由具有“提高特权”的用户运行,这真的很重要。

顺便, gets() 可能会在下一个版本中从标准C库中删除(C1X-参见N1494 WG14)。它不会从实际的C库中消失很长一段时间(20年?),但是应该用此实现(或类似的东西)代替:

#undef NDEBUG
#include <assert.h>
char *gets(char *buffer)
{
    assert("Probability of using gets() safely" == 0);
}

另一个次要细节,部分在主要问题的评论下进行了讨论。

显示的代码显然适用于C99;声明 length 在C89中,通过该函数的一部分无效。考虑到这一点,对 main() 函数不明确返回值,因为C99标准遵循C ++标准的引线,并允许您省略从 main() 效果与 return(0); 或者 return 0; 在最后。

因此,这个问题中的程序不能严格错误地错误 return 在最后。但是,我认为这是最特殊的标准化决策之一,如果标准排除了该规定,或者做了更激进的事情,例如允许无处不在但错误的事情 void main() 观察到控制返回时,结果是将成功状态返回到环境。可悲的是,不值得战斗以使标准的这一方面发生变化 - 但是作为个人风格的决定,我没有利用授予的许可来省略最终 returnmain(). 。如果代码必须与C89编译器合作,则应具有明确的 return 0; 最后(但随后声明 length 也必须修复)。

您也可以使用递归来完成。我认为在使用循环时看起来比它更好。

只需用字符串调用该方法,然后在方法中打印char之前,请再次使用相同的字符串调用该方法,减去第一个char。

这将以相反的顺序打印出您的字符串。

您应该使用 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数组, 无效的 终止字符串),编译器感到困惑。

利用 putc 或者 putchar, , 作为 puts 指定要服用 char* 而你正在喂养它 char.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top