tags:

views:

92

answers:

3

Hi,

I have simplified an issue that I've been having trying to isolate the problem, but it is not helping.

I have a 2 dimensional char array to represent memory. I want to pass a reference to that simulation of memory to a function. In the function to test the contents of the memory I just want to iterate through the memory and print out the contents on each row.

The program prints out the first row and then I get seg fault.

My program is as follows:

#include <stdio.h>

#include <stdlib.h>

#include <ctype.h>

#include <string.h>

void test_memory(char*** memory_ref)  {

    int i;
    for(i = 0; i < 3; i++)  {
        printf("%s\n", *memory_ref[i]);
    }
}

int main()  {
    char** memory;
    int i;
    memory = calloc(sizeof(char*), 20);
    for(i = 0; i < 20; i++)  {
        memory[i] = calloc(sizeof(char), 33);
    }

    memory[0] = "Mem 0";
    memory[1] = "Mem 1";
    memory[2] = "Mem 2";

    printf("memory[1] = %s\n", memory[1]);

    test_memory(&memory);

    return 0;
}

This gives me the output:

memory[1] = Mem 1
Mem 0
Segmentation fault

If I change the program and create a local version of the memory in the function by dereferencing the memory_ref, then I get the right output:

So:

#include <stdio.h>

#include <stdlib.h>

#include <ctype.h>

#include <string.h>

void test_memory(char*** memory_ref)  {

    char** memory = *memory_ref;
    int i;
    for(i = 0; i < 3; i++)  {
        printf("%s\n", memory[i]);
    }
}

int main()  {
    char** memory;
    int i;
    memory = calloc(sizeof(char*), 20);
    for(i = 0; i < 20; i++)  {
        memory[i] = calloc(sizeof(char), 33);
    }

    memory[0] = "Mem 0";
    memory[1] = "Mem 1";
    memory[2] = "Mem 2";

    printf("memory[1] = %s\n", memory[1]);

    test_memory(&memory);

    return 0;
}

gives me the following output:

memory[1] = Mem 1
Mem 0
Mem 1
Mem 2

which is what I want, but making a local version of the memory is useless because I need to be able to change the values of the original memory from the function which I can only do by dereferencing the pointer to the original 2d char array.

I don't understand why I should get a seg fault on the second time round, and I'd be grateful for any advice.

Many thanks

Joe

+4  A: 

Try:

printf("%s\n", (*memory_ref)[i]);

The current version is equivalent to

*(*(memory_ref + i));

This is because the [] operator has higher precedence than the dereference *. Which means that when i is larger than 0 you try to read memory after the char*** temporary memory_ref

The second version is equal to (*memory_ref)[i] which means that you will be indexing the correct memory.

EDIT: The reason it works on the first iteration is because:

*(*(memory_ref + 0)) == *((*memory_ref) + 0)
Andreas Brinck
This works. Thanks very much. I'm not sure why though.I would guess that the brackets allow the dereferencing operation to complete before trying to access the result of the dereferencing operation.That still doesn't explain the behaviour of the first string in the array printing though. Why didn't I get seg fault first time round?Many thanksJoe
Joe
See my edited answer, `[]` has higher precedence than `*`.
Andreas Brinck
@Joe as for why it worked on the first time round, see my edited answer.
Andreas Brinck
Legend. Nice explantion thank you. Appreciate the time. :-)
Joe
+2  A: 

This looks like a precedence issue. The [] is getting evaluated first, and the * second. What you would need is something like the following for your first code example ...

printf("%s\n", (*memory_ref)[i]);
Sparky
+1  A: 

The quick fix is to use

printf("%s\n", (*memory_ref)[i]);

But I suspect you have an problem in the lines

 memory[0] = "Mem 0";

These do not copy the string "Mem 0" into your memory array. They make memory[i] point to the string.

You need to explicitly copy the data using strncpy

e.g. char s = "Mem 0"; strncpy( memory1, s, max( strlen(s) + 1, 29) ) // max of 30= (29 char + '\0' as that is the row length you allocated - better to #define this as a constant

Mark