tags:

views:

561

answers:

5

I have a 2-D array of characters e.g. char aList[numStrings][maxLength]. ideally, during program execution I want to be able to modify the contents of aList i.e. add, amend or delete entries. Since aList will be subject to change, I don't want to have to recompile my program after every such change to modify aList. So I want to write aList out to a text file at program end and then read it back into aList at the commencement of the next program run.

However, I don't know at program start what is the value of numStrings. (I am not using C99 so I can't use a VLA, and pick up a count of previous strings from an external file.) I could, of course, set numStrings to an artificially high value but that grates!

Is there a way to populate aList without knowing the value of numStrings? I don't think there is (I have looked at related questions) but is there another way of achieving what I need?

A: 

You can dynamically allocate the array:

char **aList;
int i;

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

for (i = 0; i < maxLength; i++)
{
    aList[i] = malloc(maxLength);
}

If, by any chance, you can use C++ instead of C, you could always use a C++ vector:

std::vector<std::vector<char> > aList;
jgottula
@jgottula: as I said, I don't know the value of numStrings. And I'm using C.
paoloricardo
Ah, got it. numStrings can be a variable, but you can also use realloc to resize the array.
jgottula
Why would you use a vector of vectors of `char` in C++ instead of a vector of `std::string` like a normal person would?
Chris Lutz
@jgottula: but I could read the value of numStrings from an external files (as I initially intimated)
paoloricardo
Storing the numStrings as the first value of the file is a half-assed solution in my opinion. Some dope will inevitably break your program by adding three lines (or worse, removing three lines) and forgetting to change the entry count at the beginning, and then where are you?
Chris Lutz
@Chris: Because I'm abnormal! :)
jgottula
A: 

The situation you've described is precisely what malloc is for -- allocating a variable-length block of memory.

Mark Rushakoff
@mark: see my comment to @jgottula
paoloricardo
@mark: sorry, I see that I could read the value of numStrings from an external file
paoloricardo
You could store the number in the file (i.e. as the first line in the file), or you could make two passes over the file - count the number of strings to get your array size, then actually store the strings.
Mark Rushakoff
@Mark: I've used a separate external file to hold control information previously and this has worked well
paoloricardo
My thoughts on storing a line count in the file are in the comments to another answer here, and I won't repeat them, but in my opinion the two-pass solution is a much better one, even with the massive performance hit you're bound to encounter from it. However, you can eliminate both the performance hit and the problems with storing a value first by using a linked list.
Chris Lutz
@Chris: I note your points about using an external file. I will be looking at the linked list idea.
paoloricardo
A: 

If your plan is to populate while reading in the file you could do one of two things.

Either store the number of strings as the first element in the file, then the suggestion by jgottula would work well.

Or, must you use an array? You could read them directly into a linked list, and then when finished reading, move them into an array, and free up the linked list.

James Black
@James: I had thought of storing the value of numStrings in an external file but hadn't thought of malloc(). The linked list idea is useful too.
paoloricardo
I think there are more than a few things wrong with storing the value of `numStrings` in an external file, or storing it anywhere for that matter, but it's not my design decision. If it was, however, I would definitely go with the linked list. It's really easy to implement, and gives you all sorts of nice benefits.
Chris Lutz
A: 

You could use a dynamically allocated array. Use malloc() to make one, realloc() to change the size of one, and free() when you're done with it. But this has already been covered by another answer.

Another alternative is to use a linked list. That way you don't have to realloc() every time you want to extend your array - realloc() can be rather expensive if it has to copy the entire array to a new location.

Chris Lutz
@Chris: thanks, see my reply to @James
paoloricardo
+4  A: 

If you really want to be able to remove items from the middle of the grid (your questions isn't clear on this), you'll need some kind of multiply linked structure. These are often used to implement sparse arrays, so you can probably find one pre-made.

I'm talking about something like this:

+---+  
| A |  
+-|\+  
  | \  
  |  \  
  |   \  
  |    \
  |     +----+----+----+  
  |     | C0 | C1 | C2 | ...  
  |     +--|-+----+--|-+  
  |        |         |
  |        |         |  
+-V--+  +--V-+       | +----+
| R0 |->|a0,0|-------+>|a0,3|--> ...
+----+  +--|-+    +--V-+----+
| R1 |-----+----->|a1,2|--> ...
+----+     |      +--|-+
 ...       V         |
          ...        V
                    ...

Where A is the root node of the object, C is an array of column pointers, R is an array of row pointers, and each cell points to it next neighbor along both its row and column. All cells not explicitly represented are assumed to have some default value (usually NULL or 0).

It is a simple idea, but a fairly picky implementation, with lots of chances to mess up, so use a debugged library if you can.

dmckee
+1 for the ASCII gfx :) - did u use a tool to create that?
waqasahmed
No tool, just patience.
dmckee