我有一个函数,必须通过一些定界符将从文件中读取的行溢出到单词中(由另一个函数进行定界符检查),但是我的代码通过不包含在定界符列表中的定界符来分割字符串[数组分隔符]:
void getIdentifiers() {
FILE *filePointer;
char fileName[FILENAME_MAX], line[256], identifier[100];
char delimiter[] = {
'[', ']', '(', ')', ';', '!', '=', '>', '<', '|', '*', '/', ':',
'&', '%', ' ', '\n', '\t', '"', '{', '}', ',', '-', '+', '#' };
int cnt = 0, inWord = 0, isString = 0, isSingleLineComment = 0, isMultiComment = 0, isChar = 0;
printf("\n Enter filename:\n");
flush(stdin);
if (!fgets(fileName, FILENAME_MAX, stdin)) {
printf("\nError reading filename");
return;
}
if (fileName[strlen(fileName) - 2] != 'c' || fileName[strlen(fileName) - 3] != '.') {
printf("\nInvalid source file name\n");
return;
}
fileName[strlen(fileName) - 1] = '\0';
filePointer = fopen(fileName, "r");
if (filePointer == NULL) {
printf("\nError opening file");
return;
}
while (fgets(line, sizeof(line) / sizeof(line[0]), filePointer) != NULL) {
if (ferror(filePointer)) {
printf("\nError reading the file");
return;
}
int i = 0, j = 0;
while (line[i]) {
//multi line comment check
if (line[i] == '/' && line[i + 1] == '*')
isMultiComment = 1;
//single line comment
if (line[i] == '/' && line[i + 1] == '/')
isSingleLineComment = 1;
//ending multi line comment
if (line[i] == '*' && line[i + 1] == '/' && isMultiComment == 1)
isMultiComment = 0;
//checking for string
if (line[i] == '"' && isString == 0)
isString = 1;
else if (line[i] == '"' && isString == 1)
isString = 0;
//check if assignment char is in quote
if (line[i] == '\'' && isChar == 0)
isChar = 1;
else if (line[i] == '\'' && isChar == 1)
isChar = 0;
//splitting textline into words
if (inWord==0) {
if (!isDelimiter(delimiter, line[i])) {
inWord = 1;
identifier[j] = line[i];
j++;
} else {
i++;
continue;
}
} else {
//ending word
if (isDelimiter(delimiter, line[i])) {
inWord = 0;
identifier[j] = 0;
j = 0;
// identifier checking
if (!isString && !isMultiComment && !isSingleLineComment
&& !isChar) {
cnt++;
printf("\n%s", identifier);
}
} else {
identifier[j] = line[i];
j++;
}
}
i++;
}
isSingleLineComment = 0;
}
printf("\n Number of identifiers is %d", cnt);
}
int isDelimiter(char *delim, char c) {
int i = 0;
while (delim[i]) {
if (delim[i] == c)
return 1;
i++;
}
return 0;
}
我尝试读取的文件包含:
Turbo direct injection
预期输出为:
Turbo
direct
injection
但是我得到了
Turbo
di
ect
inject
o
答案 0 :(得分:0)
输入文件末尾是否有换行符?
{编辑添加}
您的程序假定每个单词后面都有一个定界符,因为仅当isDelimiter(delimiter, line[i])
为真( inWord 不为0)时才显示该单词,因此,如果文件中恰好包含未显示涡轮直接喷射(最后一个字符为'n')
答案 1 :(得分:0)
主要问题是delimiter
字符数组不是正确的C字符串:您必须在初始化程序的末尾添加一个显式的空字节:
char delimiter[] = { '[', ']', '(', ')', ';', '!', '=', '>', '<',
'|', '*', '/', ':', '&', '%', ' ', '\n', '\t', '"', '{', '}',
',', '-', '+', '#', '\0' };
或者,您可以使用字符串常量:
char delimiter[] = "[]();!=><|*/:&% \n\t\"{},-+#";
您的代码中还有更多问题:
flush(stdin)
具有未定义的行为。如果您要舍弃先前对scanf()
的调用中的待处理输入,请使用显式循环。
您应该从fileName
中删除结尾的换行符,但不要认为它存在。例如,使用此衬纸:
fileName(strcspn(fileName, "\n")] = '\0';
在从头开始访问字符之前,您应该验证字符串长度。按照编码,如果用户在换行符之前输入单个字符,则您将具有未定义的行为。首先删除换行符,然后使用它:
size_t len = strlen(fileName);
if (len < 3 || fileName[len - 2] != '.' || fileName[len - 1] != 'c') {
printf("\nInvalid source file name\n");
return;
}
不需要sizeof(line) / sizeof(line[0])
,根据C语言中的定义,char
是1
。
如果ferror(filePointer)
返回有效指针,则对fgets()
进行测试是没有意义的。
匹配i
时,您必须将/*
加2,否则会误解序列/*/
,此外,您不应继续在注释中扫描{{1} }和/或字符串定界符。
如果出于相同的原因匹配//
,则必须退出循环。
如果您在字符串中,则应将//
识别为转义符,并接受\
作为字符串的一部分。此外,您不应该扫描字符串中的注释。
与字符常量相同的注释。
如果文件包含很长的标识符(> 99个字符),包括内部注释或字符串,则可能会有缓冲区溢出。
您忘记关闭源文件
答案 2 :(得分:-1)
char **mystrtok(const char *str, const char *del, int alowempty)
{
char **result = NULL;
const char *end = str;
size_t size = 0;
int extrachar;
while(*end)
{
if((extrachar = !!strchr(del, *end)) || !*(end + 1))
{
/* add temp variable and malloc / realloc checks */
/* free allocated memory on error */
if(!(!alowempty && !(end - str)))
{
extrachar = !extrachar * !*(end + 1);
result = realloc(result, (++size + 1) * sizeof(*result));
result[size] = NULL;
result[size -1] = malloc(end - str + 1 + extrachar);
strncpy(result[size -1], str, end - str + extrachar);
result[size -1][end - str + extrachar] = 0;
}
str = end + 1;
}
end++;
}
return result;
}