运行以下 C 程序时出现分段错误

rap*_*ire 3 c arrays for-loop string-literals undefined-behavior

该 C 程序将行星名称作为参数,并打印它们是否是行星。好案例正在发挥作用

./planets Venus Mercury

但如果我添加坏情况,我就会得到Segmentation Fault

./planets Venus Mercury mercury

这可能是什么原因?提前致谢。

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

#define NUM_PLANETS 9

int main(int argc, char* argv[]) {
    char *planets[] = { "Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Pluto" };
    int i, j;
    for (i = 1; i < argc; i++) {
        for (j = 0; j < NUM_PLANETS; j++) {
            if (strcmp(argv[i], planets[j]) == 0) {
                printf("%s is planet %d\n", argv[i], j + 1);
                break;
            }
        }
        if (j == NUM_PLANETS) {
            printf("%s is not a planet\n", argv[i]);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

chq*_*lie 7

该代码具有未定义的行为,因为数组的初始值设定项planets只有 8 个条目,而不是 9 个条目(即 的值)NUM_PLANETS。当在 8 个条目中找不到命令行字符串参数时,将其与 进行比较planets[8],这是超出数组末尾的访问,并且很可能是无效指针,从而在由 取消引用时导致分段错误strcmp

您应该在初始化程序中添加缺少的条目"Neptune",并且应该根据数组的大小计算条目的数量。

这是修改后的版本:

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

int main(int argc, char *argv[]) {
    const char *planets[] = {
        "Mercury", "Venus", "Earth", "Mars", "Jupiter",
        "Saturn", "Uranus", "Neptune", "Pluto"
    };
    int num_planets = sizeof(planets) / sizeof(*planets);
    int i, j;
    for (i = 1; i < argc; i++) {
        for (j = 0; j < num_planets; j++) {
            if (strcmp(argv[i], planets[j]) == 0) {
                printf("%s is planet %d\n", argv[i], j + 1);
                break;
            }
        }
        if (j == num_planets) {
            printf("%s is not a planet\n", argv[i]);
        }
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以在中添加空指针终止符planets

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

int main(int argc, char *argv[]) {
    const char *planets[] = {
        "Mercury", "Venus", "Earth", "Mars", "Jupiter",
        "Saturn", "Uranus", "Neptune", "Pluto", NULL
    };

    for (int i = 1; i < argc; i++) {
        for (int j = 0;; j++) {
            if (!planets[j]) {
                printf("%s is not a planet\n", argv[i]);
                break;
            }
            if (strcmp(argv[i], planets[j]) == 0) {
                printf("%s is planet %d\n", argv[i], j + 1);
                break;
            }
        }
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

冥王星是否应该出现在阵列中是有争议的。如果你包括矮行星,其他候选行星也应该出现:阋神星(Eris)、豪美亚(Haumea)、鸟神星(Makemake)、共工(Gonggong)、类星体(Quaoar)、塞德娜(Sedna)、谷神星(Ceres)、奥喀斯(Orcus)和萨拉西亚(Salacia)……