strcat 分段错误
这里第二次调用 strcat
会产生分段错误,为什么?
#include <unistd.h>
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
int main (int argc, char * argv[])
{
char command[250];
//if(scanf("%199s", command) == 1)
gets(command);
puts(command);
int pipeIntId;
char whitespaceseparator[2]=" ";
char pidstring [30];
int pid= getpid();
sprintf(pidstring,"%d", pid);
char * whitespace_and_pid;
whitespace_and_pid = strcat(whitespaceseparator,pidstring);
char * command_and_pid;
command_and_pid=strcat(command,whitespace_and_pid); // here's the problem, I guess
if((mkfifo("pipe"/*pipeName*/,0666))==-1)
{
perror("error creating pipe 1");
exit(1);
}
if((pipeIntId=open("pipe",/*pipeName*/O_WRONLY))==-1)
{
perror("error creating pipe 2");
exit(1);
}
int written;
written=write(pipeIntId,command_and_pid,250); // send the command + the pid
close(pipeIntId);
return 0;
}
The second call to strcat
here is generating a segmentation fault, why?
#include <unistd.h>
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
int main (int argc, char * argv[])
{
char command[250];
//if(scanf("%199s", command) == 1)
gets(command);
puts(command);
int pipeIntId;
char whitespaceseparator[2]=" ";
char pidstring [30];
int pid= getpid();
sprintf(pidstring,"%d", pid);
char * whitespace_and_pid;
whitespace_and_pid = strcat(whitespaceseparator,pidstring);
char * command_and_pid;
command_and_pid=strcat(command,whitespace_and_pid); // here's the problem, I guess
if((mkfifo("pipe"/*pipeName*/,0666))==-1)
{
perror("error creating pipe 1");
exit(1);
}
if((pipeIntId=open("pipe",/*pipeName*/O_WRONLY))==-1)
{
perror("error creating pipe 2");
exit(1);
}
int written;
written=write(pipeIntId,command_and_pid,250); // send the command + the pid
close(pipeIntId);
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
“字符串连接”是学习 C 语言时应该放弃的习惯用法。它不仅会导致大量缓冲区溢出的错误,而且还会导致错误。这也是超级低效的。在您的代码中,您可以在
snprintf
格式字符串中包含空格(您应该使用它来代替sprintf
)。只要有可能,请尝试使用
snprintf
在一个步骤中完全组装一个字符串。这将所有缓冲区长度检查合并到一个地方,并且很难出错。如果事先不知道输出的大小(您应该比该长度多分配一个字节,以便空终止符不会截断您的输出)。"String concatenation" is an idiom you should drop when learning C. Not only does it lead to a lot of bugs with overflowing buffers; it's also super inefficient. In your code, you could just have included the space in the
snprintf
format string (you should be using it in place ofsprintf
).Whenever possible, try to assemble a string entirely in one step using
snprintf
. This consolidates all of the buffer length checking into one place and makes it really hard to get wrong. You can also callsnprintf
with a 0 size argument to get the length that the combined string would be, in order to find out what size to allocate, if the size of the output is not known in advance (you should allocate one more byte than this length so that the null terminator does not truncate your output).我尝试了您的代码,并且还看到第二个
strcat()
上的段错误。我发现command[250]
是在我系统上的堆栈上的whitespaceseparator[2]
之后立即分配的:例如(这里
command
开始"foo..."
),事情是这样布局的:我不能保证在您的系统上也会发生同样的情况(即使在同一编译器的不同版本之间,堆栈上的局部变量的布局也可能有所不同) ,但似乎有可能。在我的系统中,发生的情况如下:
正如其他人所说,strcat() 将第二个字符串附加到第一个字符串(结果将等于第一个参数)。因此,第一个
strcat()
溢出whitespaceseparator[]
(并将whitespaceseparator
返回为whitespace_and_pid
):第二个 < code>strcat() 尝试将
whitespace_and_pid
(==whitespaceseparator
) 附加到command
处的字符串。副本的第一个字符将覆盖command
处字符串的终止 0:复制继续...
并将继续复制
" 1234 1234 1234"
...直到它脱离进程地址空间的末尾,此时您会遇到段错误。I tried your code, and also see the segfault on the second
strcat()
. I found thatcommand[250]
is allocated immediately afterwhitespaceseparator[2]
on the stack on my system:e.g. (here
command
begins"foo..."
), things are layed out like this:I can't guarantee that the same happens on your system (layout of locals on the stack may vary even between different versions of the same compiler), but it seems likely. On mine, here is exactly what happens:
As others have said,
strcat()
appends the second string to the first (and the result will be equal to the first argument). So, the firststrcat()
overflowswhitespaceseparator[]
(and returnswhitespaceseparator
aswhitespace_and_pid
):The second
strcat()
tries to appendwhitespace_and_pid
(==whitespaceseparator
) to the string atcommand
. The first character of the copy will overwrite the terminating 0 of the string atcommand
:The copy continues...
and will carry on copying
" 1234 1234 1234"
... until it falls off the end of the process address space, at which point you get a segfault.strcat
不会按照你的想法做。它修改第一个参数指向的字符串。在本例中,该字符串包含在 2 字节数组中,因此会溢出。strcat
doesn't do what you think. It modifies the string pointed to by its first parameter. In this case, that string is contained in a 2-byte array, which is therefore overrun.为了避免缓冲区溢出错误,但使用
strcat
时,您应该使用strncat
函数。To avoid buffer overflow errors, but use
strcat
you should to usestrncat
function.您的 get 调用可能已经添加了足够的字符,从而在任何时候都会导致未定义的行为。
Your gets call could have added sufficient characters already to cause undefined behavior at about anytime.
whitespaceseparator
不够大,无法包含连接的字符串,因此会导致未定义的行为。使用
gets
通常也不受欢迎。whitespaceseparator
isn't big enough to contain the concatenated string, so you're causing undefined behaviour.Using
gets
is normally frowned upon, too.strcat
通常是不安全的,因为它可以愉快地溢出缓冲区,就像您的情况一样。首先,
whitespaceseparator
只有两个字节大?你确定这就是你想要的吗?然后将 pidstring 连接到它?我认为你把论点搞混了。但一般来说,如果您对缓冲区大小不太小心,
strcat
将导致难以调试的崩溃。有更安全的替代方案。strcat
is generally unsafe because it can happily overrun buffers, like it does in your case.First of all,
whitespaceseparator
is only two bytes large? Are you sure that's what you want? And you concatenatepidstring
to it? I think you got the arguments mixed up.In general though,
strcat
will cause hard-to-debug crashes if you're not very careful with your buffer sizes. There are safer alternatives.