Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

malloc question

Status
Not open for further replies.

bobetko

Programmer
Jan 14, 2003
155
US
I am C beginner, trying to create dynamic list of the strings.
Initially I would like to have, for example:
char item[5][5];. {"car", "cow", "pen", etc...}
If I run out of space (rows) I want to do realloc to have char item[10][5];.
If I run out of characters I want to have char item[10][10]; etc..
Please somebody explain to me how to use malloc and realloc to do this.

I also have couple of issues listed below.

Here is my code:
Code:
struct list {
    int sz;             //size
    char item[1][5];    
};
struct list mylist;


The part I don't understand is why this does work:
Code:
     mylist.item[3][0] = 'x';
     mylist.item[3][1] = 'y';
     mylist.item[3][2] = '\0';     
     mylist.item[3][15] = 'a';    //this works also
     printf("%s", item[3]);       //I get "xy" printed

1) This code executes without any errors. To me, it seems that it should produce some error since my char array is declared with char item[1][5];
2) Why would I use malloc to reserve space?
3) is it maybe that I am doing overflow but OS (Linux Fedora Core 2) doesn't know that I am overwriting who knows what and eventually program or computer will crash?

thanks in advance
 
The malloc() function always allocates a linear (1D;) chunk of bytes. It does not know about 2D, 3D etc arrays. The realloc() function allocates a new chank then move the old contents (byte by byte) and returns a pointer to it. It does not know is it 1D, 2D etc array.

So it's your responsibility to rearrange properly a contents by hands if you will change (logically) extents of 2D array. But you must declare constant extents in a structure declaration. You can't change item array member extents on the fly (at run time).

Of course, the snippet above is incorrect. For example,
Code:
struct list {
    int sz;             //size
    char item[1][5];    /* 5 bytes only */
};
struct list mylist; /* sizeof(int) + 5 + padding bytes */
...
mylist.item[3][15] = 'a';    //this works also (he-he;)
/* But an offset of the target byte is 5*3+15 == 30  */
/* so you have array[5] but assign array[30] - crash */
You may catch memory exception or may not, in both cases your memory is overlapped and the program will crashed sooner or later.

If you want to create dynamic list of the strings forget 2D arrays. Redesign your data structures completely.
Try to define a structure representing a node of a list of strings (where a string is represented by dynamically allocated 1D array of char). Create new nodes (by malloc) then link it in the list. It's a standard (and a very instructive;) excercise...
 
You are right, I have to exercise more...

Here is another question.
I am sure this is easy for you...

Code:
struct list {
    int sz;             //size
    char item[1][5];    /* 5 bytes only */
};
Then I have function which will initialize list:
Code:
struct list *initlist(num) {
    struct list *lp;
    if ((lp = (struct list *)malloc(sizeof lp)) == NULL)
          return NULL;
    lp.sz = 0;
    return lp;
}

Here is the problem.
1) I don't know how to use malloc. How can I see size of my structure from within the function? The way I have it now I get size of pointer (4 bytes.)
2) I need also function to reallocate when I run out of space. Can you show me example of realloc?
3) what ** (two stars mean)? I have seen in other people's programs someting like **lp = something .... What is **lp?

Trivial questions. I know.

PS. about changing the strategy... instead of char item[1][5];. I am planning to use char *item[1]; I believe it's better approach. But issue I have now is to learn to use malloc.

Thanks
 
Dynamic List of strings.

Please tell me if this is ok:

Code:
#include <stdio.h>
#include <stdlib.h>
struct list {
    char *item[1];
    int count;
    int capacity; 
};

struct list *init(int capacity)
{
    struct list *obj = malloc(sizeof *obj);
    if (obj) {
        obj = malloc(sizeof *obj->item * capacity);
        printf("%d\n", sizeof *obj * capacity);
        if (!obj) {
            free(obj); obj=NULL;
        } else {
            obj->capacity=capacity;
            obj->count=0;
        }
    }
    return obj;
}

int main(void) {
     struct list *lp;
     lp = init(3);
     lp->item[1] = "string11";
     lp->item[2] = "string22";
     lp->item[3] = "string33";

     printf("%d\n", sizeof *lp);
}

I assume if I would like to do:
Code:
      lp->item[4] = "string44";
I would have to do realloc first.

Questions:
1) So, for how much I have to realloc?
Let say I want to have 10 elements. So does it mean that I have to realloc for (10 * 4) + 8 = 48. (10 element * 4 bytes for an item) + 8 (capacity and count). Is my math correct.
Do I have to do anything for my array of chars. Does those have to be calculated in?

2) Is my malloc above correct?

Thanks.
 
For a beginner, this is a pretty complex exercise. Your program will not work this way because of a simple fact. If you are using array notation to declare an array you can’t change this size of this array later because the name of the array, eventhough it is a pointer, it is a constant read-only pointer.
Sure you can allocate another chunk of memory and copy every thing to it somehow, but you can’t make your array name point to this new place in memory, it is a constant.

You need to declare your array using a pointer notation and if it is 2 dimensional array it will be pointer to pointer.

Another approach is to study the linked list data structure, which is also will lead you to use the pointer to pointer notation.

There is a free pointer tutorial on the net, I suggest that you study it “very well” before continuing with your program, her is the link.



You will find it extreamly easier to progress after investing some time with this tutorial.

By the way, C/C++ compiler will not check or even complain if you index beyond the array boundaries. Your program will simply crash at some point.

Best of luck


Walid Magd

The primary challenge of every software development team is to engineer the illusion of simplicity in the face of essential complexity.
-Grady Booch
 
The sizeof operator has two forms:
- sizeof expression
- sizeof(type name/alias) /* in ()! */
In the 1st case an expression does not evaluated, only size of its result (value) yielded. So sizeof lp (1st case) returns sizeof of a pointer to a structure, not a size of a structure.
To obtain the proper value for malloc you may write:
1st form: sizeof *lp
2nd form: sizeof(struct list)
You may use alias (for example, I hate to write struct in var declarations):
Code:
typedef struct node
{
... /* members */
} Node, *NodePtr;
/* Now use: */
Node x;
...
NodePtr px = malloc(sizeof(Node)); /* No need to cast in C*/
/* and so on... */
I think you must read about list data structure before try to solve your problem. Now your struct list is not a list. At best it's a prototype of a list node (alas, without the key point: next node link field;).
So you have two problems now:
1. How to allocate new strings (see posts above)
2. How to add these new instances into a list (read books;).
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top