我是C语言的新手,我创建了一个函数,该函数从字符串中删除特殊字符并返回一个新字符串(不包含特殊字符)。
乍一看,这似乎运行良好,我现在需要在(巨大)文本文件(一百万个句子)的行上运行此功能。在几千行/句(大约4,000个句子)之后,我遇到了段错误。
我对C语言中的内存分配和字符串没有太多的经验,我试图弄清楚我的代码有什么问题,不幸的是,没有运气。 这是代码:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
char *preproccessString(char *str) {
// Create a new string of the size of the input string, so this might be bigger than needed but should never be too small
char *result = malloc(sizeof(str));
// Array of allowed chars with a 0 on the end to know when the end of the array is reached, I don't know if there is a more elegant way to do this
// Changed from array to string for sake of simplicity
char *allowedCharsArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// Initalize two integers
// i will be increased for every char in the string
int i = 0;
// j will be increased every time a new char is added to the result
int j = 0;
// Loop over the input string
while (str[i] != '\0') {
// l will be increased for every char in the allowed chars array
int l = 0;
// Loop over the chars in the allowed chars array
while (allowedCharsArray[l] != '\0') {
// If the char (From the input string) currently under consideration (index i) is present in the allowed chars array
if (allowedCharsArray[l] == toupper(str[i])) {
// Set char at index j of result string to uppercase version of char currently under consideration
result[j] = toupper(str[i]);
j++;
}
l++;
}
i++;
}
return result;
}
这是程序的其余部分,我认为问题可能在这里。
int main(int argc, char *argv[]) {
char const * const fileName = argv[1];
FILE *file = fopen(fileName, "r");
char line[256];
while (fgets(line, sizeof(line), file)) {
printf("%s\n", preproccessString(line));
}
fclose(file);
return 0;
}
答案 0 :(得分:5)
您有几个问题。
sizeof(str)
是指针的大小,而不是字符串的长度。您需要使用char *result = malloc(strlen(str) + 1);
+ 1
用于终止空字节。
result[j] = '\0';
在return result;
之前
一旦发现该字符与允许的字符匹配,就无需继续遍历其余允许的字符。在break
之后添加j++
。
您的main()
函数永远不会释放preprocessString()
的结果,因此您可能内存不足。
while (fgets(line, sizeof(line), file)) {
char *processed = preproccessString(line);
printf("%s\n", processed);
free(processed);
}
如果在结果字符串中有调用者传递,而不是在函数中分配它,则可以解决其中的大多数问题。只需在char[256]
函数中使用两个main()
数组即可。
int main(int argc, char *argv[])
{
char const* const fileName = argv[1];
FILE* file = fopen(fileName, "r");
char line[256], processed[256];
while (fgets(line, sizeof(line), file)) {
processString(line, processed);
printf("%s\n", processed);
}
fclose(file);
return 0;
}
然后只需更改功能,以使参数为:
void preprocessString(const char *str, char *result)
答案 1 :(得分:1)
一个好的经验法则是确保每个malloc / calloc调用都有一个空闲空间。
Valgrind是一个值得关注的好工具。很好地捕获此类错误。
答案 2 :(得分:1)
以下建议的代码:
strchr()
的特性还检查终止的NUL字节free()
allowedCharsArray
移动到“文件静态范围”,因此不必在每次通过循环时都重新初始化,并标记为“ const”以帮助编译器捕获错误,现在是建议的代码:(注:按评论编辑)
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
char *preproccessString(char *str)
{
// Create a new string of the size of the input string, so this might be bigger than needed but should never be too small
char *result = calloc( sizeof( char ), strlen(str)+1);
if( !result )
{
perror( "calloc failed" );
return NULL;
}
// Array of allowed chars
static const char *allowedCharsArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// Loop over the input string
for( int j=0, i=0; str[i]; i++)
{
if( strchr( allowedCharsArray, (char)toupper( str[i] ) ) )
{
// Set char at index j of result string to uppercase version of char currently under consideration
result[j] = (char)toupper(str[i]);
j++;
}
}
return result;
}
答案 3 :(得分:1)
您的代码中存在一些主要问题:
分配的内存量不正确,sizeof(str)
是指针中的字节数,而不是它指向的字符串的长度,这也是不正确的。您应该写char *result = malloc(strlen(str) + 1);
从未释放在preproccessString
中分配的内存,这会导致内存泄漏,并可能导致程序在很多大文件上耗尽内存。
您不要在result
字符串的末尾设置空终止符
较少的问题:
fopen()
是否成功。preproccessString
中有一个错字,应该是preprocessString
isalpha
代替测试每个字母char
值传递给unsigned char
时,应将toupper
的值强制转换为char
,因为toupper
可能是带符号的类型,而EOF
对于负值是未定义的除了#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
// transform the string in `str` into buffer dest, keeping only letters and uppercasing them.
char *preprocessString(char *dest, const char *str) {
int i, j;
for (i = j = 0; str[i] != '\0'; i++) {
if (isalpha((unsigned char)str[i])
dest[j++] = toupper((unsigned char)str[i]);
}
dest[j] = '\0';
return dest;
}
int main(int argc, char *argv[]) {
char line[256];
char dest[256];
char *filename;
FILE *file;
if (argc < 2) {
fprintf(stderr, "missing filename argument\n");
return 1;
}
filename = argv[1];
if ((file = fopen(filename, "r")) == NULL) {
fprintf(stderr, "cannot open %s: %s\n", filename, strerror(errno));
return 1;
}
while (fgets(line, sizeof(line), file)) {
printf("%s\n", preprocessString(dest, line));
}
fclose(file);
return 0;
}
。这是修改后的版本:
mogrify -resize 350 *.jpeg
答案 4 :(得分:0)
我认为问题在于您正在使用malloc从堆中分配内存,并且由于您一次又一次地调用此函数而导致内存不足。 要解决此问题,您必须在preprocessString函数返回的指针上调用free()函数 在您的主要区块
char *result=preprocessString(inputstring);
//Do whatever you want to do with this result
free(result);