繁体   English   中英

交换函数中的分段错误

[英]segmentation fault in swap function

我正在忙着为我的学习写一行代码。 我已经在分配上做得很远了,但我一直遇到同样的问题。 在交换功能上,当输入的字符(单词和单词2)不在主“字典”字符串中时,我一直遇到分段错误。 有人可以向我解释是什么导致了问题,我该如何解决? 抱歉,如果还不清楚,我刚开始学习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("- %s\n", 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("%d\n", 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;
            }
        }
}

细分错误很可能发生在这里:

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

实际上,i>可能会大于字典的大小,并且如果您的字典包含3个元素,而您尝试访问第4个元素,则您正在访问未知区域或内存,这会导致分段错误。 解决方案是确保您的for循环在字典的最后一个元素处停止,使用上面注释中提出的解决方案πάνταῥεῖ。

如果您自己发现实际错误,对学生的学习将是最有帮助的,尽管Marco和πάνταῥεῖ可能是正确的。 但是,这里需要考虑一些事情,因为这绝对不是您作为程序员遇到的最后一个段错误(仅本月我至少有20个)。

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

通常,如果您尝试读取数组末尾的内存,则很有可能发生段错误,或者在其他情况下出现乱码数据。 官方的说法实际上来自C ++的父语言C,因为访问数组末尾会导致“未定义的行为”。 或者,就像在USENET上曾经说过的那样,“编译器让恶魔从你的鼻子里飞出来是合法的”。 该行为是完全不可预测的。 值得庆幸的是,这种未定义的行为通常是段错误。

顺便说一句,如果您尝试访问未初始化的数组,则可能会发生类似的异常情况。

现在,由于您正在通过循环访问数组的元素,因此另一个可能的原因是循环继续超出您认为的位置。 有时修改代码是有帮助的,这样循环的迭代器(在您的情况下为i在每次迭代中都被打印出来。 这可以帮助您了解循环是否超出了应有的范围。

简而言之,请检查...

  1. 在尝试读取或写入它们之前,是否已初始化所有数组?
  2. 我的循环是否在预期的地方开始和停止? 检查“一对一”错误(即从1而不是0开始),无限循环(忘记增加迭代器或停止条件永远不为真)以及其他逻辑错误。
  3. 我是否要在数组末尾读/写?
  4. 如果使用C字符串,是否会忘记NULL终止符?

除了调试器(您应该了解如何使用它)之外,诸如valgrind之类的工具也有助于查找内存错误的原因。 通常,它可以将您指向发生段错误的确切代码行。

我已经发现问题出在strcmp中。 我知道自己找出问题是学习的最佳方法,我尝试了一下,但我无法弄清楚为什么它会返回段错误。 由于这是我的第五项任务,所以我只是想知道数组和指针的工作方式。 我假设该数组已经被初始化为'NULL',正如我已经在addWord函数中比较了指向'NULL'的指针一样。 当然,这对我来说很愚蠢。 我可能自己没有解决过这个问题,但这仍然是我不会忘记的事情。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM