即使我尝试在 C 中创建文件也找不到文件时出现分段错误

Segmentation fault when file is not found even if I try to create it in C

我正在编写将文本附加到文件的代码。 它在 WriteToFile 的开头使用 fopen 所以即使文件不存在,它也会创建它。

但是,当我根本不输入任何文件时会发生什么?根本没有争论?只是 ./a.out?

分段错误。

我不知道为什么,在我看来我做的一切都很好,避免了任何问题。

int main(int argc, char **argv)
{
    
    char file_name[30] = "file.txt";
    
    printf("%s",file_name); /* for debugging : doesn't print it */
    
    if (0 != argc)
    {
        strcpy(file_name, argv[1]);
    }
    
    WriteToFile(file_name);
    
}

或 (以防我不能真正将字符串文字放入 char 数组):

char file_name[30];
    
    if (0 == argc)
    {
       strcpy(file_name, "file.txt");
    }
    else
    {
        strcpy(file_name, argv[1]);
    }

对于这两种情况,我得到

Segmentation fault (core dumped)

if (0 != argc)

argc 值通常是(a) 参数的计数,包括 程序名称。因此,运行 ./a.outargc 为一而不是零。而且,由于 argv[argc] 通常是 NULL,取消引用它不会很好地结束 :-)

如果你想确保另一个参数可用,你可以使用:

if (argc > 1) {            // Have both argv[0] AND argv[1].
    nowSafeToUse(argv[1]);
}

C11 标准更详细地说明:

If they are declared, the parameters to the main function shall obey the following constraints:

  • The value of argc shall be nonnegative.
  • argv[argc] shall be a null pointer.
  • If the value of argc is greater than zero, the array members argv[0] through argv[argc-1] inclusive shall contain pointers to strings, which are given implementation-defined values by the host environment prior to program startup. The intent is to supply to the program information determined prior to program startup from elsewhere in the hosted environment. If the host environment is not capable of supplying strings with letters in both uppercase and lowercase, the implementation shall ensure that the strings are received in lowercase.
  • If the value of argc is greater than zero, the string pointed to by argv[0] represents the program name; argv[0][0] shall be the null character if the program name is not available from the host environment. If the value of argc is greater than one, the strings pointed to by argv[1] through argv[argc-1] represent the program parameters.
  • The parameters argc and argv and the strings pointed to by the argv array shall be modifiable by the program, and retain their last-stored values between program startup and program termination.

关于这一行的旁白:

printf("%s",file_name); /* for debugging : doesn't print it */

如果这不是打印,可能是因为标准输出是行缓冲的(如果它被确定为交互式设备则默认,否则完全缓冲)。

由于最后没有输出 \n,这些字符可能仍位于某个缓冲区中,准备写入。崩溃可能会在不刷新缓冲区的情况下终止进程。所以一个简单的解决方案可能只是使用以下之一:

printf("%s",file_name);
puts(file_name);

另外另一个,如果您输入的文件名超过 29 个字符,您将会遇到麻烦,因为它会溢出 file_name,允许[=36=] 最后也是。

更好的方法可能是直接使用默认字符串或 argv[1](不复制),例如:

int main(int argc, char **argv) {
    char *file_name = (argv > 1)
        ? argv[1]
        : "file.txt";
    printf("%s\n", file_name); // for debugging : probably does print it :-)
    
    WriteToFile(file_name);
}

(a) 标准 不需要 因为它允许特定于实现的差异,但这是通常的情况。具体来说,短语:

... which are given implementation-defined values by the host environment prior to program startup. The intent is to supply to the program information determined prior to program startup from elsewhere in the hosted environment.

几乎意味着它可以为所欲为:-)

可以找到相关答案(虽然是非重复问题)here

argc 为 1 时,argv 被视为指向 char 的 2 个指针的数组。第一个是有效指针(通常指向程序名称),第二个是 NULL.

argv[1] 访问 argv 的第二个元素。如果不提供参数,argc 将为 1,argv[1] 将为 NULL。因此,您正在取消引用 NULL 指针。

条件 0 != argc 应改为 argc >= 2argc > 1,条件 0 == argc 应改为 argc < 2argc <= 1

您必须考虑程序的名称,因此您应该改为 if (argc >= 2)。参见 man

The value of the argc argument is the number of command line arguments. The argv argument is a vector of C strings; its elements are the individual command line argument strings. The file name of the program being run is also included in the vector as the first element; the value of argc counts this element. A null pointer always follows the last element: argv[argc] is this null pointer.

argv[1] 表示索引 1 但在 C 中你从索引 0 开始。


固定码

int main(int argc, char **argv)
{
    
    char file_name[30] = "file.txt";
    
    printf("%s",file_name); /* for debugging : doesn't print it */
    
    if (argc >= 2)
        strcpy(file_name, argv[1]);
    else
        return 1;  // exit program with error code.
    WriteToFile(file_name);
    return 0; // exit with success
}