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

发布于 2024-09-17 04:55:02 字数 722 浏览 0 评论 0原文

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

我应该做什么?

I am using Linux.
I am trying to write a program in c that will print a string backward.
Here is my code:

#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]);
    }
}

And here is the error:

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.

What should I do?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

℉服软 2024-09-24 04:55:02

忘记函数 gets() 的存在——它是致命的。请改用 fgets() (但请注意,它不会删除行尾的换行符)。

您想一次输入一个字符:使用 putchar() 将其写入标准输出。不要忘记在循环后的输出中添加换行符。

另外,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--) = 0; length--)

最后一个替代方案使用了 C99 中添加的功能(很久以前就在 C++ 中可用)。

此外,我们还可以讨论 length 是否是变量的适当名称。最好将其重命名为 ipos 或类似的名称,因为虽然它被初始化为输入的长度,但它实际上用作数组索引,而不是用作任何东西的长度。

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


为什么 gets() 是致命的?

第一个互联网蠕虫 - 1988 年的 Morris 蠕虫 - 利用了 fingerd 使用 gets() 而不是 fgets() 的程序。从那时起,许多程序都因为使用 gets() 而不是 fgets() 或其他替代方案而崩溃。

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

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

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

#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; 相同。

因此,严格来说,这个问题中的程序不能因为最后没有返回而被归咎于错误。然而,我认为这是更特殊的标准化决定之一,并且如果标准将这一规定排除在外,我会更喜欢它 - 或者做一些更激进的事情,例如允许普遍存在但错误的 void main()观察到当控制从那里返回时,结果是成功状态返回到环境。不幸的是,不值得为改变标准的这一方面而奋斗 - 但作为个人风格的决定,我不会利用授予的许可来省略来自 的最终 返回 main()。如果代码必须与 C89 编译器一起使用,则它应该在末尾显式返回 0;(但随后也必须修复 length 的声明)。

Forget that the function gets() exists - it is lethal. Use fgets() instead (but note that it does not remove the newline at the end of the line).

You want to put a single character at a time: use putchar() to write it to stdout. Don't forget to add a newline to the output after the loop.

Also, for (length = length; length >= 0; length--) is not idiomatic C. Use one of:

  • for ( ; length >= 0; length--)
  • for (length = strlen(string) - 1; length >= 0; length--)
  • for (int length = strlen(string) - 1; length >= 0; length--)

The last alternative uses a feature added to C99 (which was available in C++ long before).

Also, we could debate whether length is the appropriate name for the variable. It would be better renamed as i or pos or something similar because, although it is initialized to the length of the input, it is actually used as an array index, not as the length of anything.

Subjective: Don't put a space between the name of a function and its parameter list. The founding fathers of C don't do that - neither should you.


Why is gets() lethal?

The first Internet worm - the Morris worm from 1988 - exploited the fingerd program that used gets() instead of fgets(). Since then, numerous programs have been crashed because they used gets() and not fgets() or another alternative.

The fundamental problem is that gets() does not know how much space is available to store the data it reads. This leads to 'buffer overflows', a term which can be searched for in your favourite search engine that will return an enormous number of entries.

If someone types 150 characters of input to the example program, then gets() will store 150 characters in the array which has length 100. This never leads to happiness - it usually leads to a core dump, but with carefully chosen inputs - often generated by a Perl or Python script - you can probably get the program to execute arbitrary other code. This really matters if the program will ever be run by a user with 'elevated privileges'.

Incidentally, gets() is likely to be removed from the Standard C library in the next release (C1x - see n1494 from WG14). It won't vanish from actual C libraries for a long time yet (20 years?), but it should be replaced with this implementation (or something similar):

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

One other minor detail, discussed in part under the comments to the main question.

The code shown is clearly for C99; the declaration of length part way through the function is invalid in C89. Given that, it is 'OK' for the main() function not to explicitly return a value, because the C99 standard follows the lead of the C++ standard and allows you to omit the return from main() and the effect is the same as return(0); or return 0; at the end.

As such, the program in this question cannot strictly be faulted for not having a return at the end. However, I regard that as one of the more peculiar standardizing decisions, and would much prefer it if the standards had left that provision out - or done something more radical like allowing the ubiquitous but erroneous void main() observing that when control returns from that, the result is that a success status is returned to the environment. It isn't worth fighting to get that aspect of the standard changed - sadly - but as a personal style decision, I don't take advantage of the licence granted to omit the final return from main(). If the code has to work with C89 compilers, it should have the explicit return 0; at the end (but then the declaration of length has to be fixed too).

风吹过旳痕迹 2024-09-24 04:55:02

您还可以使用递归来完成此操作。我认为使用循环时看起来更好。

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

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

You can also use recursion to do it. I think it looks nicer then when using a loop.

Just call the method with your string, and before printing the char in the method, call the method again with the same string, minus the first char.

This will print out you string in reversed order.

面如桃花 2024-09-24 04:55:02

第一:

NEVER NEVER NEVER NEVER NEVER使用gets();它在您的代码中引入故障点。无法告诉 gets() 目标缓冲区有多大,因此,如果您传递一个大小为容纳 10 个字符的缓冲区,并且输入流中有 100 个字符,gets() code> 会很乐意将这额外的 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()

First:

NEVER NEVER NEVER NEVER NEVER use gets(); it will introduce a point of failure in your code. There's no way to tell gets() how big the target buffer is, so if you pass a buffer sized to hold 10 characters and there's 100 characters in the input stream, gets() will happily store those extra 90 characters in the memory beyond the end of your buffer, potentially clobbering something important. Buffer overruns are an easy malware exploit; the Morris worm specifically exploited a gets() call in sendmail.

Use fgets() instead; it allows you to specify the maximum number of characters to read from the input stream. However, unlike gets(), fgets() will save the terminating newline character to the buffer if there's room for it, so you have to account for that:

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

Now that's out of the way...

Your error is coming from the fact that puts() expects an argument of type char *, but you're passing an argument of type char, hence the "pointer from integer without cast" message (char is an integral type). To write a single character to stdout, use putchar() or fputc().

月牙弯弯 2024-09-24 04:55:02

您应该使用 putchar 而不是 puts

所以这个循环:

for (length = length; length>=0; length--){
    puts (string[length]);
}

将是:

for (length = length; length>=0; length--){
    putchar (string[length]);
}

putchar 将采用单个字符作为参数并将其打印到 stdout,这就是你想要的。另一方面,puts 会将整个字符串打印到 stdout。因此,当您将单个字符传递给需要整个字符串(字符数组、NULL 终止字符串)的函数时,编译器会感到困惑。

You should use putchar instead of puts

So this loop:

for (length = length; length>=0; length--){
    puts (string[length]);
}

Will be:

for (length = length; length>=0; length--){
    putchar (string[length]);
}

putchar will take a single char as a parameter and print it to stdout, which is what you want. puts, on the other hand, will print the whole string to stdout. So when you pass a single char to a function that expects a whole string (char array, NULL terminated string), compiler gets confused.

oО清风挽发oО 2024-09-24 04:55:02

使用 putcputchar,因为 puts 被指定为获取 char* 并且您正在向其提供 >字符。

Use putc or putchar, as puts is specified to take a char* and you are feeding it a char.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文