程序应该能够打开像myFile.txt
这样的文件, 所有Tough它的真名是myFile
没有扩展名.txt
。 所以我按顺序写了名为removeFileExtension()
的function
来实现这一目标。
它确实通过将string
从text
复制到filename
来打开我的文件:
strcpy(filename,text);
FILE *fp = fopen(filename, "r");
所以我试图检查text
和我处理的有什么区别string
来自removeFileExtension
是。
为了检查它是否有效,我配上了一种名为strComparison()
的function
, 当它为合格时返回0
,如果不相等,则返回1
。 问题是,删除文件扩展名后,它显示两个字符串 是合格的,但我仍然无法打开文件。
当我输入./a.out myFile.txt
我的比较function
返回0
时, 它是相等的,但fopen()
仍然无法打开文件, 我分别得到了一个Segmentation fault
.
有人看到这里的问题吗? 为什么我要Segmentation fault
?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void removeFileExtension(char *haystack);
int strComparison(char *one, char *two);
int main(int argc, char const *argv[])
{
//----------------------------------------------------------------------------
// CHECK INPUT VALIDITY
//
if (argc != 2)
{
printf("Usage: ./ass2 [file-name]n");
return 1;
}
//----------------------------------------------------------------------------
// OPEN FILE (INITIAL)
//
char filename[32];
strcpy(filename, argv[1]);
FILE *fp = fopen(filename, "r"); //FOPEN
//FILE *fp = fopen("start_of_story txt", "r"); // this way does work
if (fp == NULL)
{
// IF NOT FOUND: REMOVE EXTENSION
removeFileExtension(filename);
char text[] = "myFile ";
int ret_val = -1;
ret_val = strComparison(filename, text);
if (ret_val == 0)
printf("[DEBUG] equaln");
else
printf("[DEBUG] unequaln");
printf("[DEBUG] ret_val: %dn", ret_val);
printf("[DEBUG] '%s'n", filename);
FILE *fp = fopen(filename, "r"); //FOPEN
// IF STILL DOESN'T WORK: ERROR
if (fp == NULL)
{
printf("[ERR] Could not read file %s.n", filename);
return 3;
}
}
//--------------------------------------------------------------------------
// READ DATA (INITIAL)
//
int bufsize = 1024;
char *buffer = malloc(bufsize * sizeof(char)); //MALLOC
if (!buffer)
{
printf("[ERR] Out of memory.n");
return 2;
}
fseek(fp, 0, SEEK_SET);
fread(buffer, bufsize, 1, fp);
printf("[DEBUG] %sn", buffer);
fclose(fp); //FCLOSE
free(buffer);
buffer = NULL;
return 0;
}
void removeFileExtension(char *haystack)
{
char needle[1] = ".";
char *retp; // return pointer
retp = strstr(haystack,needle);
if (*retp == '.')
{
while (*retp != ' ')
{
*retp++ = ' ';
}
printf("[DEBUG] %sn", haystack);
}
}
int strComparison(char *one, char *two)
{
do
{
printf("[DEBUG] '%c' == '%c'n", *one, *two);
if (*one++ != *two++)
{
return 1; // return 1 if unqual
}
}
while ( (*one != ' ') || (*two != ' ') );
return 0; // return 0 if qual
}
结果输出:
user@host ~/Desktop $ ./a.out myFile.txt
[DEBUG] myFile
[DEBUG] 'm' == 'm'
[DEBUG] 'y' == 'y'
[DEBUG] 'F' == 'F'
[DEBUG] 'i' == 'i'
[DEBUG] 'l' == 'l'
[DEBUG] 'e' == 'e'
[DEBUG] equal
[DEBUG] ret_val: 0
[DEBUG] 'myFile'
[ERR] Could not read file myFile.
user@host ~/Desktop $
引用C11
,第7.24.5.7章
char *strstr(const char *s1, const char *s2);
strstr
函数定位s1
字符串中的第一个匹配项,由 字符串中指向的字符序列(不包括终止 null 字符) 由s2
.
因此,传递给strstr
的两个参数都必须是字符串。在您的情况下,
char needle[1] = ".";
不是字符串。您没有为空终止符留出空间。要么使用
char needle[2] = ".";
,至少,或者,char needle[ ] = ".";
,或者,char const* needle = ".";
作为副作用,每当达到removeFileExtension()
调用时,您都会面临未定义的行为
也就是说,当心!!
你正在做类似的事情
retp = strstr(haystack,needle);
if (*retp == '.')
即,从strstr()
中取消引用返回的指针。如果strstr()
返回 NULL 指针,您将再次陷入 UB 中。
编辑:
对于那些仍然对字符串有困惑的人,请查看第 §7.1.1 章中的定义(强调我的)
字符串是以第一个 null结尾并包含第一个 null 的连续字符序列 字符。[...]
至少我发现了问题:
删除文件扩展名后,我仍然 尝试打开旧文件指针fp
,这 给了我空指针。新文件指针 仅在if(fp == NULL){...}
体内 存在于if
-语句的作用域内。
所以我创建了一个test_pointer
,它首先查看 该文件甚至存在,如果没有,他会删除扩展名。 比我再次尝试打开文件,这次是fp
.
感谢大家的提示,尤其是 苏拉夫·戈什 为您的改进建议!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int removeFileExtension(char *haystack);
int main(int argc, char const *argv[])
{
char filename[64];
strcpy(filename, argv[1]);
//----------------------------------------------------------------------------
// CHECK INPUT VALIDITY
//
if (argc != 2)
{
printf("Usage: ./ass2 [file-name]n");
return 1;
}
//----------------------------------------------------------------------------
// CHECK FILE EXISTENSE
//
FILE *test_pointer = fopen(filename, "r"); //FOPEN
if (test_pointer == NULL) // if not found: remove extension
{
int ret_val = removeFileExtension(filename);
if (ret_val == -1)
{
printf("[ERR] Could not remove file extension.n");
return 3;
}
}
//----------------------------------------------------------------------------
// OPEN FILE (INITIAL)
//
FILE *fp = fopen(filename, "r"); //FOPEN
if (fp == NULL) // if still doesn't work: error
{
printf("[ERR] Could not read file %s.n", filename);
return 3;
}
//----------------------------------------------------------------------------
// READ DATA (INITIAL)
//
int bufsize = 1024;
char *buffer = malloc(bufsize * sizeof(char)); //MALLOC
if (!buffer)
{
printf("[ERR] Out of memory.n");
return 2;
}
fseek(fp, 0, SEEK_SET);
fread(buffer, bufsize, 1, fp);
fclose(fp); //FCLOSE
printf("[DEBUG] %sn", buffer);
free(buffer); //FREE
buffer = NULL;
return 0;
}
int removeFileExtension(char *haystack)
{
char needle[] = ".";
char *retp; // return pointer
retp = strstr(haystack,needle);
if(!retp) // to prevent UB
return -1;
if (*retp == '.')
{
while (*retp != ' ')
{
*retp++ = ' ';
}
printf("[DEBUG] %sn", haystack);
}
return 0;
}