交换功能出现分段故障

segmentation fault in swap function

本文关键字:分段 故障 功能 交换      更新时间:2023-10-16

我正忙着写一行学习用的代码。这个作业我已经做了很多了,但我总是遇到同样的问题。在交换功能上,当输入字符时,我一直遇到分段错误(word &不在主"字典"字符串中的Word2)。有人能告诉我是什么原因导致了这个问题,我该如何解决它吗?对不起,如果有什么不清楚,我刚刚开始学习c++。

出现分段错误的代码:

  void swapWords(char **dict, char *word, char *word2)
{
    int i; 
    int d;
    int x;
    int y;
    char *tmp;

    while (1){  
        for(i = 0; i < MAX_NUMBER_OF_WORDS; i++)
        { 
            if(strcmp(word, dict[i]) != 0)
            {    
                if(i == MAX_NUMBER_OF_WORDS -1)
                {
                    printf("Cannot swap words. Atleast one word missing in the dictionary.n");
                    goto error;
                }
            }
            else
            {
                x = i;
                break;  
            }
        }
        for(d = 0; d < MAX_NUMBER_OF_WORDS; d++)
        { 
            if(strcmp(word2, dict[d]) != 0)
            {    
                if(d == MAX_NUMBER_OF_WORDS -1)
                {
                    printf("Cannot swap words. Atleast one word missing in the dictionary.n");
                    goto error;
                }
            }
            else
            {
                y = d;
                break;
            }
        }
        tmp = dict[x];
        dict[x] = dict[y];
        dict[y] = tmp;
        error: break;
    }
}

整个代码:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#define MAX_NUMBER_OF_WORDS 10
void swapWords(char **dict, char *word, char *word2)
{
    int i; 
    int d;
    int x;
    int y;
    char *tmp;

    while (1){  
        for(i = 0; i < MAX_NUMBER_OF_WORDS; i++)
        { 
            if(strcmp(word, dict[i]) != 0)
            {    
                if(i == MAX_NUMBER_OF_WORDS -1)
                {
                    printf("Cannot swap words. Atleast one word missing in the dictionary.n");
                    goto error;
                }
            }
            else
            {
                x = i;
                break;  
            }
        }
        for(d = 0; d < MAX_NUMBER_OF_WORDS; d++)
        { 
            if(strcmp(word2, dict[d]) != 0)
            {    
                if(d == MAX_NUMBER_OF_WORDS -1)
                {
                    printf("Cannot swap words. Atleast one word missing in the dictionary.n");
                    goto error;
                }
            }
            else
            {
                y = d;
                break;
            }
        }
        tmp = dict[x];
        dict[x] = dict[y];
        dict[y] = tmp;
        error: break;
    }
}
void removeWord(char **dict, char *word)
{
    int i;
    int d;
    for(i = 0; i < MAX_NUMBER_OF_WORDS; i++)
    { 
        if(strcmp(dict[i], word) == 0)
        {   dict[i] = NULL;
            for(d = i+1; d < MAX_NUMBER_OF_WORDS; d++)
            { if(dict[d] == NULL)
                { dict[i] = dict[d-1];
                    dict[d-1] = NULL;
                    break;
                }
            }
            break;
        }
    }
}
void printDict(char **dict)
{
    int i = 0;
    if(dict[0] == NULL)
    {
        printf("The dictionary is empty.n");
    }
    else{
    while (dict[i] != NULL)
    {
        printf("- %sn", dict[i]);
        i++;
    }
    }
}
void addWord(char **dict, char *word)
{
    int d;
    char *word1;
            for(d = 0; d < MAX_NUMBER_OF_WORDS; d++)
            {
                if (dict[d] == NULL)
                {           
                word1 = (char*) malloc(sizeof(char)*(strlen(word) + 1));
                strcpy(word1, word);
                dict[d] = word1;
                break;
                }
            }
}
int numberOfWordsInDict(char **dict)
{
    int i = 0;
    int d;
    for (d = 0; d < MAX_NUMBER_OF_WORDS; d++){
    if(dict[d] != NULL)
    {
        i++;
    }
}
    return i;
}
int main()
{
    char *dict[MAX_NUMBER_OF_WORDS] = {};
    char word[36];
    char word2[36];
    char c;
    int i;
    while(printf("Command (a/p/r/s/q): "))
    {
    scanf(" %c", &c);
    switch (c){
    case 'p':   printDict(dict);
                break;
    case 'a':   printf("Enter a word: ");
                scanf("%s", word);
                addWord(dict, word);
                break;
    case 'n':   i = numberOfWordsInDict(dict);
                printf("%dn", i);
                break;
    case 'r':   printf("Remove a word: ");
                scanf("%s", word);
                removeWord(dict, word);
                break;
    case 's':   printf("Swap two words:n");
                printf("Enter first word: ");
                scanf("%s", word);
                printf("Enter second word: ");
                scanf("%s", word2);
                swapWords(dict, word, word2);
                break;
    case 'q':   return 0;
            }
        }
}

尽管马可和π α ντα ρ ε ν可能是对的,但如果你自己发现实际的错误,对你作为学生的学习将是最有帮助的。然而,这里有一些事情需要考虑,因为这绝对不会是你作为程序员的最后一个段错误问题(仅这个月我就遇到了至少20个)。

段错误几乎总是由试图修改或读取它没有读取或修改权限的内存的代码引起的。当程序启动时,会给它一块内存(RAM)供它使用。出于安全原因,不允许任何程序使用该块之外的内存。还有其他限制因素在起作用。

作为一般规则,如果您试图读取超过数组末尾的内存,那么您有很高的风险获得段错误,或者在其他情况下,数据乱码。关于这一点的官方这个词实际上来自C, c++的父语言,因为访问数组的末尾会导致"未定义行为"。或者,正如USENET上曾经说过的那样,"编译器让恶魔从你鼻子里飞出来是合法的"。这种行为是完全不可预测的。值得庆幸的是,这种未定义的行为通常是段错误。

顺便说一下,如果您试图访问未初始化的 数组,也会发生类似的奇怪情况。

NOW,由于您通过循环访问数组的元素,另一个可能的原因是您的循环继续超出了您认为的位置。有时,修改代码使循环的迭代器(在您的示例中是i)在每次迭代中打印出来是有帮助的。这可以帮助您发现循环是否超出了应有的范围。

总之,check…

    在我尝试读或写之前,我是否初始化了所有的数组他们吗?
  1. 我的循环是否在我预期的地方开始和停止?检查"off-by- 1"错误(即从1开始而不是0),无限循环(忘记自增迭代器或停止条件是)
  2. 我是否试图读取/写入超过数组的末尾?
  3. 如果我正在使用c字符串,我忘记了NULL终止符吗?

除了调试器(您应该学习如何使用它)之外,像valgrind这样的工具在查找内存错误的原因方面也很有用。通常,它可以指向发生段错误的代码行。

我自己发现了问题出在字符串上。我知道自己找出问题是最好的学习方式,我也试过了,但我就是弄不明白为什么它会返回segfault。由于这是我的第五次赋值,我只是刚刚了解数组和指针是如何工作的。我假设数组已经初始化为'NULL',正如我已经在addWord函数中将指针与'NULL'进行比较。当然,我认为这是非常愚蠢的。我可能没有自己解决这个问题,但它仍然是我不会再忘记的事情。

最有可能的分割错误发生在这里:

if(strcmp(word, dict[i]) != 0)

事实上,很有可能i>变得比你的字典的大小更大,如果你的字典有3个元素,你试图访问第4个,你正在访问一个未知的区域或ram,这会导致分割错误。解决方案是确保你的for循环在字典的最后一个元素处停止,上面的评论中提出了π ντα ρ ε ν的解决方案。