无法创建反转字符串的程序
我正在使用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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
忘记函数
gets()
的存在——它是致命的。请改用fgets()
(但请注意,它不会删除行尾的换行符)。您想一次输入一个字符:使用 putchar() 将其写入标准输出。不要忘记在循环后的输出中添加换行符。
另外,
for (length = length; length >= 0; length--)
不是惯用的 C. 使用以下之一:for (; length >= 0; length--)
for (length = strlen(string) - 1;
for (int length = strlen(string) - 1; length >= 0; length--) = 0; length--)
最后一个替代方案使用了 C99 中添加的功能(很久以前就在 C++ 中可用)。
此外,我们还可以讨论
length
是否是变量的适当名称。最好将其重命名为i
或pos
或类似的名称,因为虽然它被初始化为输入的长度,但它实际上用作数组索引,而不是用作任何东西的长度。主观:不要在函数名称与其参数列表之间放置空格。 C 语言的创始人不会这样做——你也不应该这样做。
为什么 gets() 是致命的?
第一个互联网蠕虫 - 1988 年的 Morris 蠕虫 - 利用了
fingerd
使用gets()
而不是fgets()
的程序。从那时起,许多程序都因为使用gets()
而不是fgets()
或其他替代方案而崩溃。根本问题是
gets()
不知道有多少空间可用于存储它读取的数据。这会导致“缓冲区溢出”,您可以在您最喜欢的搜索引擎中搜索该术语,该术语将返回大量条目。如果有人在示例程序中输入了 150 个字符,那么
gets()
将在长度为 100 的数组中存储 150 个字符。这永远不会带来幸福 - 它通常会导致核心转储,但是通过精心选择的输入(通常由 Perl 或 Python 脚本生成),您可能可以让程序执行任意其他代码。如果程序将由具有“提升权限”的用户运行,这一点确实很重要。顺便说一句,
gets()
可能会在下一个版本中从标准 C 库中删除(C1x - 请参阅 WG14)。它不会在很长一段时间内(20 年?)从实际的 C 库中消失,但应该用此实现(或类似的东西)替换:另一个小细节,在评论中部分讨论主要问题。
显示的代码显然是针对 C99 的;函数中
length
的声明在 C89 中无效。鉴于此,main()
函数不显式返回值是“可以”的,因为 C99 标准遵循 C++ 标准的引导,并允许您省略的返回main()
效果与最后的return(0);
或return 0;
相同。因此,严格来说,这个问题中的程序不能因为最后没有返回而被归咎于错误。然而,我认为这是更特殊的标准化决定之一,并且如果标准将这一规定排除在外,我会更喜欢它 - 或者做一些更激进的事情,例如允许普遍存在但错误的
void main()
观察到当控制从那里返回时,结果是成功状态返回到环境。不幸的是,不值得为改变标准的这一方面而奋斗 - 但作为个人风格的决定,我不会利用授予的许可来省略来自的最终
。如果代码必须与 C89 编译器一起使用,则它应该在末尾显式返回 0;(但随后也必须修复返回
main()length
的声明)。Forget that the function
gets()
exists - it is lethal. Usefgets()
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 asi
orpos
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 usedgets()
instead offgets()
. Since then, numerous programs have been crashed because they usedgets()
and notfgets()
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):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 themain()
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 frommain()
and the effect is the same asreturn(0);
orreturn 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 erroneousvoid 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 finalreturn
frommain()
. If the code has to work with C89 compilers, it should have the explicitreturn 0;
at the end (but then the declaration oflength
has to be fixed too).您还可以使用递归来完成此操作。我认为使用循环时看起来更好。
只需使用您的字符串调用该方法,并在打印方法中的字符之前,使用相同的字符串再次调用该方法,减去第一个字符。
这将以相反的顺序打印出您的字符串。
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.
第一:
NEVER NEVER NEVER NEVER NEVER使用
gets()
;它会在您的代码中引入故障点。无法告诉gets()
目标缓冲区有多大,因此,如果您传递一个大小为容纳 10 个字符的缓冲区,并且输入流中有 100 个字符,gets()
code> 会很乐意将这额外的 90 个字符存储在缓冲区末尾之外的内存中,这可能会破坏一些重要的内容。缓冲区溢出是一种简单的恶意软件利用; Morris 蠕虫专门利用了 sendmail 中的gets()
调用。使用
fgets()
代替;它允许您指定从输入流读取的最大字符数。但是,与gets()
不同,fgets()
会将终止换行符保存到缓冲区(如果有空间),因此您必须考虑到这一点:现在就这样了顺便说一句...
您的错误来自于
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 tellgets()
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 agets()
call in sendmail.Use
fgets()
instead; it allows you to specify the maximum number of characters to read from the input stream. However, unlikegets()
,fgets()
will save the terminating newline character to the buffer if there's room for it, so you have to account for that:Now that's out of the way...
Your error is coming from the fact that
puts()
expects an argument of typechar *
, but you're passing an argument of typechar
, hence the "pointer from integer without cast" message (char
is an integral type). To write a single character to stdout, useputchar()
orfputc()
.您应该使用
putchar
而不是puts
所以这个循环:
将是:
putchar
将采用单个字符作为参数并将其打印到stdout
,这就是你想要的。另一方面,puts
会将整个字符串打印到stdout
。因此,当您将单个字符传递给需要整个字符串(字符数组、NULL 终止字符串)的函数时,编译器会感到困惑。You should use
putchar
instead ofputs
So this loop:
Will be:
putchar
will take a single char as a parameter and print it tostdout
, which is what you want.puts
, on the other hand, will print the whole string tostdout
. So when you pass a single char to a function that expects a whole string (char array, NULL terminated string), compiler gets confused.使用
putc
或putchar
,因为puts
被指定为获取char*
并且您正在向其提供>字符。
Use
putc
orputchar
, asputs
is specified to take achar*
and you are feeding it achar
.