2

I am working on a Uni assignment here, and I've run into a problem. I am attempting to store a string input at a point inside a struct using a for-loop. Later on I intend to use the pointer to the place where the data was stored to fetch the string. Now the problem is, as I move on inside my for-loop, the address of the point changes as well. This code:

printf("B: %p\n", txt->point);
for(i = 0; i < input_sz; i++)
{
    txt->point[i] = input[i];
}
printf("A: %p\n", txt->point);

gives the output:

B: 0x7fc111803200
A: 0x7fc111803265

where B is before-value and A is after-copying value.

Any help debugging this would be very appreciated!


EDIT: Here's some more code:

The struct:

struct text_storage {
    char* start;
    char* point;
    char* end;
} typedef text_t;

Initialization function:

text_t* text_init(void *memory, size_t size)
{
    text_t* to_return;
    if(size < sizeof(text_t))
    {
        return NULL;
    }
    to_return = (text_t*) memory;
    to_return->start = to_return;

    to_return->end = to_return->start + size;
    to_return->point = to_return->start;

    printf("Start: %p, point: %p, end: %p, end-start: %d\n", to_return->start, to_return->point, to_return->end, (to_return->end - to_return->start));


    return to_return;
}

The text-store method in which the error occurs:

int text_store_entry(text_t *txt, const char *input, size_t input_sz)
{
    int to_return;
    char* begin = txt->point;
    int i;

    if(input_sz > (txt->end - txt->point))
    {
        return -1;
    }

    printf("Start: %p, point: %p, end: %p, end-start: %d\n", txt->start, txt->point, txt->end, (txt->end - txt->start));


    printf("B: %p\n", txt->point);
    for(i = 0; i < input_sz; i++)
    {
        txt->point[i] = input[i];
    }
    printf("A: %p\n", txt->point);

}

Main-function (testing purposes only):

int main(int argc, char* argv[])
{
    void* memory = malloc(10000);
    char* a = "hei pa deg din trekkbasun";
    text_t* txt;
    int memoverwritten;

    txt = text_init(memory, 10000);

    memoverwritten = text_store_entry(txt, a, (size_t)26);


    printf("got through\n");
    return 0;
}
Henrik Hillestad Løvold
  • 1,213
  • 4
  • 20
  • 46

2 Answers2

3

The problem most probably is due to the initialization of structures of type struct text_storage. Such structures contain three pointers to text. Each pointer should be initialized, possibly with a malloc. Your text_init function does not do that properly. In fact, the place where the start pointer is stored overlaps with the first bytes of the memory that you want to use.

I'm guessing that you need a structure like this:

typedef struct text_storage {
    char* start;
    char* point;
    char* end;
    char* data;
} text_t;

initialized with a function like this:

text_t text_init(void *memory, size_t size)
{
  text_t to_return;
  to_return.data = (char *) memory;
  to_return.start = to_return.data;
  to_return.end = to_return.start + size;
  to_return.point = to_return.start;
  return to_return;
}
nickie
  • 5,608
  • 2
  • 23
  • 37
  • The assignment specifies that the only heap space we are allowed to use is the one passed to the text_init function. We are not allowed to reserve heap memory outside this block. That leaves me with no malloc I'm afraid :( – Henrik Hillestad Løvold Sep 21 '13 at 10:20
  • OK, no `malloc`, see above. If you want the `memory` to store the complete structure, you'll need a struct with a last field of variable size, see [here](http://stackoverflow.com/questions/7641698/allocating-struct-with-variable-length-array-member). – nickie Sep 21 '13 at 10:25
  • Thank you! So you're using another pointer to data? How do you think about changing the start and end pointers into null-length arrays? Then they will take 0 bytes and only point to somewhere in memory, right? – Henrik Hillestad Løvold Sep 21 '13 at 10:33
  • You cannot have two zero length arrays in the same structure. You can have just one such field and it must be **the last** one. This is a trick, useful if you have structures whose actual length you don't know but only their first fields. Avoid it, if you can. – nickie Sep 21 '13 at 11:43
  • Thanks, I'm trying to follow your advice here, but I'm getting a compiler error at the line `to_return.end = to_return.start + size;`. Any idea why? I cannot see why it wouldn't work. – Henrik Hillestad Løvold Sep 21 '13 at 19:27
  • What does the compiler error say? It compiles OK here. You have `#include `, I suppose (it's needed for `size_t`). – nickie Sep 21 '13 at 20:29
0

Print txt->point in the loop and see the point at which it changes. I'm guessing it changes when assigning to txt->point[0]. I'm not fully familiar with printf, so I'm not sure what it's printing out for you, but the name of an array references the first location. If printf is printing out a pointer, txt->point[i] is always a char pointer, and printf may be dereferencing txt->point, which will get it the first entry, and then showing the address there, which you do assign when you change the point to input[i].

  • That seems to be right. The address of the point changes to the new value (+65 from the start) as it enters the first iteration, and keeps this value throughout the loop. When printing the address of txt->point[i] inside the loop, I can see that it moves 4 bytes for each iteration. Which makes sense because we're storing chars. – Henrik Hillestad Løvold Sep 21 '13 at 10:42
  • In that case, change your printf statement to print &txt->point[0], and hopefully it will remain constant, showing you that your array is not moving. Though I wouldn't have expected printf to change on every iteration as you say it does, so leaves me wondering. – Charles J. Daniels Sep 21 '13 at 11:06
  • Such debugging is not necessary, the problem is clear. In the way structures are initialized, `txt`, `&(txt->start)` and `txt->start` all point to the same address (`memory`). When you start adding text, you erase the value of `txt->start`. – nickie Sep 21 '13 at 11:47