我需要从给定的字符串或单词中删除标点符号。这是我的代码:
void remove_punc(char* *str)
{
char* ps = *str;
char* nstr;
// should be nstr = malloc(sizeof(char) * (1 + strlen(*str)))
nstr = (char *)malloc(sizeof(char) * strlen(*str));
if (nstr == NULL) {
perror("Memory Error in remove_punc function");
exit(1);
}
// should be memset(nstr, 0, sizeof(char) * (1 + strlen(*str)))
memset(nstr, 0, sizeof(char) * strlen(*str));
while(*ps) {
if(! ispunct(*ps)) {
strncat(nstr, ps, 1);
}
++ps;
}
*str = strdup(nstr);
free(nstr);
}
如果我的主要功能很简单:
int main(void) {
char* str = "Hello, World!:)";
remove_punc(&str);
printf("%s\n", str);
return 0;
}
有效!输出为Hello World
。
现在我想读取一个大文件并从文件中删除标点符号,然后输出到另一个文件。 这是另一个主要功能:
int main(void) {
FILE* fp = fopen("book.txt", "r");
FILE* fout = fopen("newbook.txt", "w");
char* str = (char *)malloc(sizeof(char) * 1024);
if (str == NULL) {
perror("Error -- allocating memory");
exit(1);
}
memset(str, 0, sizeof(char) * 1024);
while(1) {
if (fscanf(fp, "%s", str) != 1)
break;
remove_punc(&str);
fprintf(fout, "%s ", str);
}
return 0;
}
当我在Visual C ++中重新运行程序时,它报告了一个
Debug Error! DAMAGE: after Normal Block(#54)0x00550B08
,
程序中止。
所以,我必须调试代码。一切都有效,直到语句free(nstr)
被执行。
我有点迷惑不解了。有人可以帮帮我吗?
答案 0 :(得分:2)
您忘记了为null终结符设置malloc空间。改变
nstr = (char *)malloc(sizeof(char) * strlen(*str));
到
nstr = malloc( strlen(*str) + 1 );
请注意casting malloc is a bad idea,如果您要malloc
然后memset
为零,则可以使用calloc
代替那样做。
您的计划稍后会出现另一个错误。 remove_punc
函数将str
更改为指向新分配的缓冲区,该缓冲区对于没有标点符号的字符串来说足够大。但是,然后循环到fscanf(fp, "%s", str)
。这不再读入1024字节的缓冲区,而是只读取前一个无标点字符串的缓冲区大小。
因此,除非您的文件包含所有行的长度降序(删除标点符号后),否则会导致缓冲区溢出。你需要重新考虑这个循环的设计。例如,您可能让remove_punc
保持输入不变,并返回指向新分配字符串的指针,打印后您将free
。
如果你使用这个解决方案,那么使用%1023s
来避免使用fscanf缓冲区溢出(遗憾的是,这里没有简单的方法来获取变量而不是硬编码长度)。使用裸"%s"
的scanf函数与gets
一样危险。
答案 1 :(得分:1)
@MatMcNabb的答案解释了您的问题的原因。我将提出几种可以简化代码的方法,并使其不易受内存问题的影响。
如果性能不是问题,请逐个字符地阅读文件并丢弃惩罚字符。
int main(void)
{
FILE* fp = fopen("book.txt", "r");
FILE* fout = fopen("newbook.txt", "w");
char c;
while ( (c = fgetc(fp)) != EOF )
{
if ( !ispunct(c) )
{
fputc(c, fout);
}
}
fclose(fout);
fclose(fp);
return 0;
}
通过将输入字符串和输出字符串传递给malloc
,最大限度地减少对free
和remove_punc
的调用次数。
void remove_punc(char* inStr, char* outStr)
{
char* ps = inStr;
int index = 0;
while(*ps)
{
if(! ispunct(*ps))
{
outStr[index++] = *ps;
}
++ps;
}
outStr[index] = '\0';
}
并更改remove_punc
中使用main
的方式。
int main(void)
{
FILE* fp = fopen("book.txt", "r");
FILE* fout = fopen("newbook.txt", "w");
char inStr[1024];
char outStr[1024];
while (fgets(inStr, 1024, fp) != NULL )
{
remove_punc(inStr, outStr);
fprintf(fout, "%s", outStr);
}
fclose(fout);
fclose(fp);
return 0;
}
答案 2 :(得分:0)
在你的主要内容中你有以下
char* str = (char *)malloc(sizeof(char) * 1024);
...
remove_punc(&str);
...
你的remove_punc()函数获取str的地址但是当你在remove_punc函数中执行此操作时
...
*str = strdup(nstr);
...
您没有将新字符串复制到先前分配的缓冲区,您正在重新分配str以指向新行大小的缓冲区!这意味着当您从文件中读取行并且要读取的下一行比上一行更长时,您将遇到麻烦。
您应该单独保留原始缓冲区,例如返回包含新字符串的新分配缓冲区,例如返回nstr,然后释放它,当它完成或更好时,只需将原始文件逐字节复制到新文件并排除任何标点符号。那会更有效