簡體   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