我真的很难用一段非常简单的代码。
该程序采用./a.out -t=1,32,45,2
之类的参数,并在stdout中打印逗号数量。但有时执行工作正常,并且更经常抛出分段错误。
我在这个函数行substr_cnt
中找出了这个问题(我在下面的代码中也放了相应的注释):
target_counting = (char *)malloc(sizeof(char)*(strlen(target)));
实际上malloc返回NULL。如果我将sizeof(char)
改为sizeof(char *)
,那么所有的开始都像魅力一样,但我无法理解为什么会这样。此外,在main函数中我也使用malloc,甚至使用相同的行
arg_parameter = (char *) malloc(sizeof(char)*(strlen(argv[1] - 3)));
一切正常。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define strindex(target, source) ((size_t) strstr(target, source) - (size_t) target)
int substr_cnt( char *target, char *source ) {
int i=0;
int cnt=0;
char *target_counting;
//this is NOT working
target_counting = (char *)malloc(sizeof(char)*(strlen(target)));
//this is working
//target_counting = (char *)malloc(sizeof(char *)*(strlen(target)));
if (target_counting == NULL) {
printf("malloc failed\n");
return -1;
}
strcpy(target_counting, target);
while ((i=strindex(target_counting, source)) > 0) {
strncpy(target_counting, target_counting + i + 1, strlen(target_counting));
cnt++;
}
free(target_counting);
return cnt;
}
int main( int argc, char *argv[] )
{
int i;
int default_behavior = 0;
int arg_parametr_cnt;
char *arg_parameter;
if (argc == 1) {
default_behavior = 1;
} else if (argv[1][0] == '-' && argv[1][1] == 't' && argv[1][2] == '=') {
//this is working
arg_parameter = (char *) malloc(sizeof(char)*(strlen(argv[1] - 3)));
strncpy(arg_parameter, argv[1]+3, strlen(argv[1]));
printf("%s\n", arg_parameter);
arg_parametr_cnt = substr_cnt(arg_parameter, ",");
printf("commas: %d\n", arg_parametr_cnt);
}
else {
printf("wrong command line");
return 1;
}
return 0;
}
答案 0 :(得分:3)
这里有几个问题,重点是,你根本不需要分配内存。您可以实现搜索给定的子字符串而无需修改字符串,因此可以直接使用给定的argv
参数,例如
int substr_cnt(const char *haystack, const char *needle)
{
int cnt = 0;
const char *found = haystack;
while ((found = strstr(found, needle)) != NULL) {
++found;
++cnt;
}
return cnt;
}
main
中的来电相同,只是直接传递argv
arg_parametr_cnt = substr_cnt(argv[1] + 3, ",");
现在回答你的问题,除非你真的看到了
的输出printf("malloc failed\n");
我不相信,malloc
会返回NULL
,因为当你分配更多的内存时,sizeof(char*)
vs sizeof(char)
,它就可以了。
其他答案已经涵盖了程序崩溃的原因。总结
target_counting = (char *)malloc(sizeof(char)*(strlen(target)));
分配一个少于它的字符while ((i=strindex(target_counting, source)) > 0)
当strstr
的结果为NULL
时,我不确定会发生什么。 strindex
可能会返回一个负数,具体取决于您的内存布局,但我不确定。strncpy(target_counting, target_counting + i + 1, strlen(target_counting));
这不是一个真正的问题,但由于你复制了其余的字符串,你可以改用strcpy(target_counting, target_counting + i + 1)
。arg_parameter = (char *) malloc(sizeof(char)*(strlen(argv[1] - 3)));
这应该是malloc(sizeof(char) * strlen(argv[1]) - 3 + 1)
strncpy(arg_parameter, argv[1]+3, strlen(argv[1]));
再次strcpy(arg_parameter, argv[1]+3)
就足够了更新
在此版本中
int strindex(char *target, char *source)
{
char *idx;
if ((idx = strstr(target, source)) != NULL) {
return idx - target;
} else {
return -1;
}
}
您对NULL
进行了明确的测试,并采取相应的行动。
在宏版本中
#define strindex(target, source) ((size_t) strstr(target, source) - (size_t) target)
没有这样的测试。您可以通过计算strstr()
与基址target
之间的差异来确定索引。到目前为止这很好,但是当strstr()
返回NULL
时会发生什么?
指针算法由两个指针定义,指向同一个数组。一旦两个指针指向不同的数组,或者一个指向一个数组而另一个指向另一个数组,则行为是未定义的。
从技术上讲,当您计算NULL - target
时,可能会产生负值,但也可能不会。如果target
指向0x0f0a3a90
的地址,则可以0x0 - 0x0f0a3a90
并获得负值。如果target
指向0xfe830780
,则可能会将其解释为负数,然后0x0 - 0xfe830780
可能会产生正数。
但重点是,你有未定义的行为。为了进一步阅读,查找指针算法,例如, C++: Pointer Arithmetic
答案 1 :(得分:2)
你的malloc没有为null终止符分配空间,你需要malloc(strlen(string)+1)。 带有char *的malloc可以工作,因为指针(正常)长4个字节,所以你分配的内存比所需的多4倍 - 减去1个字节需要一个空终止符。
答案 2 :(得分:2)
问题可能在于:malloc(sizeof(char)*(strlen(argv[1] - 3))
中的main
。您正在从3
中减去argv[1]
。
我想你打算用:
malloc(sizeof(char)*(strlen(argv[1]) - 2)); // Allocate one more space for '\0' character
这样做会使strlen
访问未分配的内存。
您的程序可能不会在此处失败,但稍后会失败,因为它只是undefined behavior
。
答案 3 :(得分:2)
有几个缓冲区溢出,但我认为导致程序崩溃的错误如下:
strncpy(target_counting, target_counting + i + 1, strlen(target_counting));
请注意,strncpy中的字符串可能不会重叠!
我建议你做一个memmove,因为memmove可以处理重叠缓冲区:
memmove(target_counting, target_counting + i + 1, strlen(target_counting + i + 1) + 1);
答案 4 :(得分:1)
我认为你的主要问题在于:
arg_parameter = (char *) malloc(sizeof(char)*(strlen(argv[1] - 3)));
特别是在这里
strlen(argv[1] - 3)
您传递到strlen
的{{1}}地址,该地址不是有效地址。
实际上你的意思是argv[1]-3
。正如其他人所说,你也应该为strlen(argv[1]) - 3
添加一个字符\0