[英]Segmentation Fault with sprintf
我正在制作一个makefile创建器,但是我在sprintf上遇到了这个错误,最有意思的事情是,在有错误的那个之前我有多个sprintf,它们可以正常工作。
这是代码:
if ( WIFEXITED(stat) ){
if ( WEXITSTATUS(stat) ) {
if ( cFiles == 0 && cFolders == 0 ) {
Crear(path);
}
cFolders = 1;
TEMP = malloc( sizeof(char)*( strlen(direntp->d_name) + 25 ) );
if ( TEMP == NULL ) {
perror("Malloc Error: ");
exit(1);
}
if ( sprintf(TEMP, "\n%s/%s.a: force\n\t$(MAKE) -C %s\n",direntp->d_name, direntp->d_name, direntp->d_name) < 0 ) {
perror("Sprintf Error: ");
exit(1);
}
write(STDOUT_FILENO,TEMP,strlen(TEMP));
f.name = malloc( sizeof(char)*( strlen(direntp->d_name)*2 + 3 ) );
if ( f.name = NULL ) {
perror("Malloc Error: ");
exit(1);
}
//This is the one with the problem!!!
if ( sprintf(f.name, "%s/%s.a", direntp->d_name, direntp->d_name) < 0 ) {
perror("Sprintf Error: ");
exit(1);
}
l = AddToList(l,&f);
}
}
看起来您分配的TEMP似乎不够大
TEMP = malloc( sizeof(char)*( strlen(direntp->d_name) + 25 ) );
应该:
TEMP = malloc( sizeof(char)*( strlen(direntp->d_name)*3 + 25 + 1 ) );
您将打印d_name三次,并且还需要一个额外的字节作为空终止符。
同样,在这一行:
f.name = malloc( sizeof(char)*( strlen(direntp->d_name)*2 + 3 ) );
应该
f.name = malloc( sizeof(char)*( strlen(direntp->d_name)*2 + 3 + 1) );
解决空终止符。
使用这样的断言可以帮助确保您的计算正确:
int TEMP_size = strlen(direntp->d_name)*3 + 25 + 1;
TEMP = malloc(sizeof(char)*TEMP_size);
if ( TEMP == NULL ) {
perror("Malloc Error: ");
exit(1);
}
if ( sprintf(TEMP, "\n%s/%s.a: force\n\t$(MAKE) -C %s\n",direntp->d_name, direntp->d_name, direntp->d_name) < 0 ) {
perror("Sprintf Error: ");
exit(1);
}
assert(strlen(TEMP)+1==TEMP_size);
“%s /%sa”,所以我认为如果“%s”的长度为n,则整个字符串将为n * 2 + 1 + 1 + 1 + 1 + 1 = 2n + 4而不是2n + 3 ...不要忘记终止符'\\ 0',但是关于这是否会导致分段错误...我不知道...
//是的,关于这段代码中要分配的字节数,有很多错误...
您没有为此sprintf分配enougth内存:
sprintf(TEMP, "\n%s/%s.a: force\n\t$(MAKE) -C %s\n",direntp->d_name, direntp->d_name, direntp->d_name
您分配sizeof(direntp-> d_name)+25,但我看到25个字符+ 3 * sizeof(direntp-> d_name)+1个额外的字符(您的\\ 0表示字符串的结尾)
问候
除了以前的答案,还有一些注意事项:
大多数现代的类Unix系统在标准库中都有asprintf()和vasprintf(),它们自己分配缓冲区。 使用它们比计算所需的大小,分配和调用sprintf()更为简单,即使它们有点整体。
填充缓冲区,然后使用write()将其打印到stdout看起来像简单的printf()那样不必要的复杂。 除非您使用stdio无法稳定处理的内容(例如非阻塞I / O),否则将stdio用于此类任务会更好。
您执行的任务最好适合某些脚本语言(Perl,Python,Tcl,Ruby,等等),除非某些外部怪异的情况迫使您使用C;否则,您可能会遇到这种情况。 Unix中应该以C语言来实现更接近内核和底层的区域。 有关推理,请参见“ Unix编程的艺术” 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.