简体   繁体   中英

segmentation fault in swap function

im busy writing a line of code for my study. I already have gotten quite far on the assignment but i keep running into the same problem. On the swap function i keep running into a segmentation fault when a character is inputted(word & word2) that is not in the main 'dictionary' string. Could someone explain to me what is causing the problem and how i can solve it? Sorry if anything isnt clear, i've just started learning c++.

code where segmentation fault occures:

  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;
    }
}

The entire code:

#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;
            }
        }
}

Most probably the segmentation fault happens here:

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

Infact it is quite likely that that i > becomes bigger than the size of your dict and if your dict has 3 elements and you try to access the 4th you are accessing an unknown area or ram and that causes a segmentation fault. The solution is to make sure your for loop stops at the last element of the dictionary with the solution πάντα ῥεῖ has proposed in the above comment.

It will be most helpful to your studies as a student if you find the actual error yourself, though Marco and πάντα ῥεῖ may be right. However, here are a few things to think about, as this will definitely not be your last segfault problem as a programmer (I had at least 20 this month alone).

A segmentation fault is almost always caused by the code trying to modify or read memory that it doesn't have permission to read or modify. When the program starts, it is given a chunk of memory (RAM) to work with. For security reasons, no program is allowed to work with memory outside of that chunk. There are other limitations at play too.

As a general rule, if you try to read memory past the end of an array, you have a high risk of getting a segfault, or in other cases, garbled data. The official word on this actually comes from C, C++'s parent language, in that accessing past the end of an array causes "undefined behavior". Or, as it was once said on USENET, "it is legal for the compiler to make demons fly out of your nose". The behavior is totally unpredictable. Thankfully, that undefined behavior usually IS a segfault.

By the way, if you try to access an uninitialized array, similar weirdness can happen.

NOW, since you are accessing the elements of your array via a loop, another possible cause is that your loop is continuing beyond where you think it is. Sometimes it is helpful to modify your code so that the loop's iterator ( i in your case) is printed out each iteration. This can help you catch if the loop is going beyond where it should.

In short, check...

  1. Did I initialize all of my arrays before I tried to read or write them?
  2. Are my loops starting and stopping where I expected? Check for "off-by-one" errors (ie starting at 1 instead of 0), infinite loops (forgot to increment the iterator or the stop condition is never true), and other logical errors.
  3. Am I trying to read/write past the end of the array?
  4. If I'm working with a C-string, did I forget the NULL terminator?

In addition to your debugger, which you should learn how to use well, tools like valgrind are instrumental in finding the cause of memory errors. Oftentimes, it can point you to the exact line of code where the segfault is occuring.

I had figured out myself the problem was in the strcmp. I know that figuring out a problem by myself is the best way to learn and I tried, but I just couldn't figure out why it was returning a seg fault. As this is my fifth assignment I'm only just getting to know how array's and pointers work. I assumed that the array was already initialized as 'NULL', as seen I was already comparing the pointer to 'NULL' in the addWord function. To assume this is ofcourse very stupid of me. I might not have figured the problem out by myself, yet it is still something I will not be forgetting anymore.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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