尝试声明字符串数组时出现分段错误

Segmentation fault when trying to declare an array of strings

在我的程序中,我尝试将每个 argv[i] 复制到关键字 [i],但我的程序因分段错误而失败。我做错了什么?

#include <stdio.h>
#include <cs50.h>
#include <ctype.h>
#include <string.h>

int main(int argc, string argv[])    
{
    //prototype
    string keyword = "";
    //int j;

    for (int i = 0, n = strlen(argv[1]); i < n; i++)
    {
        keyword[i] = toupper(argv[1][i]);
        printf("%i-- printing letters\n", keyword[i]);
    }
}

您的主要问题:您没有为新字符串分配内存,(string keyword = "")。

在 C 中,编译时未知的每个大小都必须在 运行 时间内动态分配。

此外,您永远不会检查可能导致程序崩溃的丢失参数。

请参阅下面的代码以了解这两个修复方法

#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, string argv[])

{
    if (argc != 2)
    {
        printf("Usage: %s <word>\n", argv[0]);
        return 1;
    }
    int length = strlen(argv[1]);
    string keyword = malloc(length+1);

    for(int i = 0, n = strlen(argv[1]); i < n; i++)
    {
        keyword[i] = toupper(argv[1][i]);
        printf("%i-- printing letters\n", keyword[i]);

    }
    keyword[length]=0;
    free(keyword);
}

正如其他人所观察到的,您将变量 keyword 初始化为空字符串或指向空字符串文字的指针,具体取决于类型 string 的定义。无论哪种方式,仅当 i 等于零时,评估 keyword[i] 才有效;任何其他值——用于读或写——都是越界的。此外,在后一种情况下(指向字符串文字的指针),您不得尝试修改 keyword 指向的数组。

请特别注意,如果您尝试访问越界元素,C 不会自动扩展字符串。相反,尝试这样做会产生 "undefined behavior",并且在这种情况下表现出来的一种常见方式是以分段错误的形式出现。您可以将分段错误视为系统因试图访问不属于它的内存而关闭您的程序。

因为你不知道先验参数字符串在你复制它之前会有多长,keyword最可行的类型是char *.为了清楚起见,我将在下文中使用该类型而不是 string

如果您确实想要复制参数,那么到目前为止,最简单的方法是通过专用函数 strdup():

    char *keyword = strdup(argv[1]);

它为其参数(包括终止符)的副本分配足够的内存,复制它,returns 指向结果的指针。完成后,您必须通过 free() 函数释放生成的内存。以这种方式制作副本后,您可以将每个元素大写到位:

    for (int i = 0, n = strlen(keyword); i < n; i++)
    {
        keyword[i] = toupper(keyword[i]);
        printf("%c-- printing letters\n", keyword[i]);
    }

注意,顺便说一下,单个字符的 printf() 格式描述符是 %c,而不是 %i。您必须使用它来打印字符 作为 个字符,而不是它们的整数值。

这是为您要执行的操作编写 C 代码的最简单方法之一,尽管有许多变体。我要提供给您考虑的唯一另一个是不要完全复制参数:

    char *keyword = argv[1];

如果您以这种方式初始化 keyword,则您不会分配任何内存或制作副本;相反,您将 keyword 设置为指向 argv[1] 指向的相同字符串。您可以就地修改该字符串(尽管您不能延长它),前提是您不需要保留其原始内容。

在总结之前,我还应该观察到您的程序不检查是否确实存在参数。如果没有( argc < 2),argv[1]要么包含空指针(argc == 1)要么未定义(argc == 0; 你不太可能 运行 进入这个)。无论哪种方式,如果您的程序尝试使用 argv[1] 就好像它是指向有效字符串的指针一样,那么您的程序在这种情况下会产生未定义的行为。您应该首先测试这种情况,如果没有可用的程序参数,则以诊断消息终止。