简体   繁体   中英

Segmentation fault when indexing into char array via pointer

My code is causing a segmentation fault when accessing an array element even though that element was already accessed without a problem.

int charToInt(char a)
{
    int b;
    if(isdigit(a))
    {   
        b = a - '0' - 1;
    }
    if(isalpha(a))
    {
        b = a - 65; 
    }
    return b;   
}

int validPosition(char **array, int r, int c, char* position, int slots)
{
    int i,k;
    if(strlen(position) == 5)
    {
        if(!isalpha(position[0]) || !isdigit(position[1]) || position[2]!=' ' || (position[3]!='N' && position[3]!='E' && position[3]!='W' && position[3]!='S')) //lathos gramma
        {
            printf("\n%s", "Invalid answear.This is an example of a valid answear: A5 N");
            return 2;
        }
        if( charToInt(position[0]) > r - 1 || charToInt(position[1]) > c - 1  )//ama vgainei eksw apo ta oria
        {
            printf("\n%s", "The position you choosed is out of the bountries...");
            return 2;
        }
        printf("\n%s%c%s","position[3] is: ",position[3], " but it doesn't work >_<"); // position[3] is N 
        if(position[3] == 'N') //the problem is here <~~~~~~~~~~~~~~~~~~~<
        {
            printf("\n%s", "come on");
            if(charToInt(position[0]) + slots < r)
            {
                for(i=charToInt(position[0])-1; i<charToInt(position[0])+slots; i++)
                {
                     if(array[i-1][charToInt(position[1])-1] != '.')
                     {
                         printf("\n%s", "The position you choosed is not valid because there is oneother ship there");
                         return 2;
                     }
                }
            }
            else
            {
                printf("\n%s", "The ship is going out of the bountries...");
                return 2;
            }
        }
    }
}

When position holds the string "A9 N" , the printf correctly outputs 'N' for position[3] . For some reason when it tries to do if(position[3] == 'N') , however, a segmentation fault occurs.

Example program run:

Example of positioning: G3 E

Aircraft carrier (5 places), Give location and direction: A9 N

1

position[3] is: N but it doesn't work >_<

Well, based on your updates, it seems you have a variety of problems. For future reference, actually adding in the (possibly simplified) code showing how you were calling the function in question is better than trying to describe it using prose in a comment. There will be less guesswork for the people trying to help you.

If I'm reading your comment correctly, the code that calls validPosition looks something like this:

// "r and c are 9 and 9 in the specific example(rows columns)."
int rows = 9;
int columns = 9;

// "slots=5."
int slots = 5;

// "array is a 2d array and it contains characters(created with malloc)."
char **array = malloc(rows * columns * sizeof(char));

// "i created char position[10] in the function that called this function"
char position[10];
// "and with fgets(position, 10, stdin); i putted A9 N inside it."
fgets(position, 10, stdin);

validPosition(array, rows, columns, position, slots);

The first problem is your description of the allocation of array (I apologize if I misunderstood your comment and this isn't actually what you are doing). It should look similar to the code below for a dynamically sized two-dimensional array used with two subscripting operations ( array[index1][index2] , as it is in validPosition ). Pointers-to-pointers ( char **array ) act differently than fixed sized multi-dimensional arrays ( array[SIZE1][SIZE2] ) when you access them that way.

// each entry in array should be a pointer to an array of char
char **array = malloc(rows * sizeof(char*));
for(i = 0; i < rows; i++)
    array[i] = malloc(columns * sizeof(char));

You also need to be careful about using position after the fgets call. You should check the return value to make sure it isn't NULL (indicating an EOF or error condition). The string may not be \\0 -terminated in this case. In fact, all the elements may still be uninitialized (assuming you didn't initialized them before the call). This can lead to undefined behavior.

The next issue is that validPosition does not return a value on every code path. One example is if strlen(position) != 5 . The other is if you enter the for loop and array[i-1][charToInt(position[1])-1] != '.' is never true (that is, the ship placement is deemed valid).

As strange as it is for an English speaker to say this to a Greek author, lets ignore internationalization and focus only on the default C local. The checks on position[0] should therefore be sufficient, though you might consider allowing your users to use lowercase letters as well. When converting position[1] from 1 -based to 0 -based, however, you do not account for the case when it is '0' , which will result in charToInt returning -1 . Furthermore, you're erroneously doing the subtraction again in the second array subscript of array[i-1][charToInt(position[1])-1] .

Similarly, as pointed out by Jite and BLUEPIXY, you are doing two extra subtractions on the result of charToInt(position[0]) : one in the for loop initializer ( i=charToInt(position[0])-1 ) and one in the first array subscript of array[i-1][charToInt(position[1])-1] .

Once you fix that, you might find that you are sometimes incorrectly telling the user that their selection is invalid. This is because you are checking charToInt(position[0]) + slots < r instead of <= r .

As I mentioned in my comment, one of the accesses to array is very probably the culprit behind your segmentation violation, not position[3] == 'N' . The reason you don't see the output of printf("\\n%s", "come on"); is that your stdout appears to be line-buffered and there's no end of line to flush it. It is generally automatically flushed on normal program termination, however you're seg-faulting so that doesn't happen.

Finally, these are only the semantic errors I noticed. Stylistically, the code could also stand to be improved. For instance, it seems you're going to be implementing else if(position[3] == 'E' , else if(position[3] == 'W' , and else if(position[3] == 'S' clauses with similar logic to your if(position[3] == 'N' clause. This increases the likelihood you'll introduce an error by incorrectly copying-and-pasting and also increases your work later when you need to make a change in four places instead of one.

Since the terminology 'Segmentation Fault' I believe you are on Linux machine. Use gdb to find the cause of error. Here are the steps.

  1. Compile with additional -g flag (ex. gcc -g my_prog.c)
  2. Run debugger: gdb a.out
  3. Use 'list' command to find the line for break point (eg. first line of your function)
  4. Set breakpoint on that line with: b 25 (if 25 is that line)
  5. Run program with 'run' command
  6. Use command 'next' to execute next line of code

Now the execution will pause on that line, you can examine memory, print variable contents and stuff. But generally you want to determine on which line the execution fails and what was in which variable.

With a little playing with memory, you will easily find where the problem is. Personally, my code wont work with gdb support.

Perhaps segmentation fault at array[i-1][charToInt(position[1])-1]

i: charToInt(position[0])-1 : charToInt('A') - 1 : -1 <- Array out-of-bounds

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