views:

581

answers:

6

I want to store lines of strings dynamically using C language.

for e.g

sadasdasda5245sdf

fadfa6456

fasdf90-70=790

the number of such lines and the length of each line can be anything.Is there any way to store the whole thing dynamically.

+6  A: 

There are several data structures that allow you to add items dynamically, without having to know in advance what the maximum number of elements required are. There are linked lists, binary search trees, balanced trees, tries, heaps and many more.

Similarly, there are lots of ways of dynamically allocating strings of different lengths.

The easiest way would probably be to use a simple linked list:

typedef struct _node {
    struct _node *next;
    char *value;
} node_t;

You keep track of the head, the first item in the list, and each next field points to the next node in the list. For example, to traverse the list, you would write something like this:

currentNode = head;
while(currentNode != NULL) {
    /* do something with currentNode->value */
    currentNode = currentNode->next;
}

Without knowing what you want to do, specifically, I can't really offer any better suggestions.

What operations do you want to carry out on your data structure often? Are you going to simply be iterating through the strings, searching for strings, adding and removing strings?

IRBMe
What's wrong with an array of character pointers? Your answer doesn't really address the string storage, and the trivial way of adding nodes to a list means that the list stores the values in reverse order (which might be helpful, but probably isn't). If the string pointers are separately allocated from the array of pointers, then you can realloc() the array when necessary to grow it.
Jonathan Leffler
There's absolutely nothing wrong with a dynamically growing array of character pointers if that suits your needs. You must, however, recognise the advantages and disadvantages it has and what those give you over other data structures. Furthermore, there's no reason a linked list has to give you values in reverse order. If you keep a note of the tail in your linked list data structure, it's trivial to add nodes on to the end rather than the beginning, or use a doubly linked list to traverse in either direction.
IRBMe
The reason I didn't address the string storage is because I don't believe there is enough information in the question to really do so.
IRBMe
I think the OP is looking for the C equivalent of std::vector<std::string>. See my answer: http://stackoverflow.com/questions/1182534/dynamically-store-lines-of-strings-using-c/1182649#1182649
Jim Buck
+3  A: 
Traveling Tech Guy
+2  A: 

Run, don't walk, to the Princeton web site and get Dave Hanson's C Interfaces and Implementations. The data structure called Seq_T is perfect for building up a list of lines dynamically. Dave doesn't provide a buffering reader, but you can read lines into a finite buffer, convert the result using Text_put, and if a line is too big for one buffer, join the results using Text_cat. The CII code manages all the dynamic growth for you.

Norman Ramsey
Ouch. Your recommendation uses arrays that get realloc'ed with growth and whatnot. Not to mention that the code is not that commented (maybe because they want to sell the book) ?That data structure would be ok for a small number of strings, but it has poor performance characteristics.
njsf
@njsf: As long as the dynamic array is doubled in size at each reallocation the mean insertion time remains O(1) for each item. The cost of this approach is, of course, indeterminate latency on any given insert. This is a popular approach which compares well with lists or trees for some applications because is has O(1) access time for reads and changes.
dmckee
@njsf: the comments are indeed in the book. But there's no performance problem; I've used this library for many applications and have always had excellent results. If you find a performance problem, I want to know about details, with measurements.
Norman Ramsey
*All* arrays get realloc'ed with growth. Even the C++ std library for vector does the same thing internally. Without knowing ahead of time how many items in an array you will have, there is no CPU magic other than to realloc with growth or initially allocate an array so huge, there is no way you will need more entries (I mean, who needs more than 640k anyway? :) ).
Jim Buck
+2  A: 

If you know at some initialization time the number of strings and will not need to allocate for more, you could just use a:

char **myStrings = (char **)malloc(numStrings*sizeof(*myStrings);

and then allocation for each string:

for(int i=0; i<numStrings; i++)
    myStrings[i] = (char *)malloc(stringLength[i] + 1);

You could still allocate more dynamically if needed, though.

If you need to dynamically reallocate the array of strings:

myStrings = (char **)realloc(myStrings, numStringsNew*sizeof(myStrings));

or if a particular string needs to change its length, just realloc that particular string:

myStrings[the_one_to_realloc] = (char *)realloc(myStrings[the_one_to_realloc], stringLengthNew + 1);
Jim Buck
O(1) to fetch a specific line, better than linked list.
Liran Orevi
Yeah, this is essentially the manual equivalent to std::vector<std::string> in C++ using the STL.
Jim Buck
`x = realloc(x, ...);` may leak memory. Better use a temporary variable.
Alok
+2  A: 

There is little reason to reinvent the wheel, unlike what some answers suggest.

Do not develop your own library, while there are several free software libraries which implement such abstractions. One example, among others, is glib which has many types such as dynamically growing strings and dynamically growing lists.

bortzmeyer
Yes, it's a good idea to use an existing implementation, but it never hurts to understand the underlying algorithms that can be used to solve this kind of problem. For example, if you're going to want to process the strings in a sorted order, an underlying hash table implementation probably isn't a good idea.
caf
A: 
N 1.1