I've taking many attempts at solving this problem but failed every time.
I have an array
char *array[1024] = {};
Now I would like to add an item to the array and would also access the items by numbers
For example:
array[0] would be the first item
array[1] would be the second
array[2] would be the third item
But also I would like to know how many items are in the array so I could use something like
for(int i = 0; i <= totalitemsinarray; i++) {
print(array[i]);
}
You cannot change the size of an array in C. You can however allocate a sufficiently large array and then fill it up with entries. First, declare an array with a sufficient size, say, 1024.
char *array[1024];
Then declare a variable fill that counts the number of used slots in array. Initialize it to 0 as 0 slots are used in the beginning. Then, each time you insert an item, increment fill:
array[fill++] = ...;
...
array[fill++] = ...;
Make sure that you never attempt to insert more than 1024 items into the array, C doesn't check that for you.
For a more flexible approach, use malloc() to allocate memory for the array and then periodically enlarge it with realloc() when it's full. If you increase the array size in exponential steps (say, multiply with Φ = 0.5 + 0.5 √2 ≈ 1.61), this runs in O(1) amortised time per entry inserted.
There is no way to do what you're asking directly with C. One option could be if you knew that only certain values were valid. For example, you have an array of char *s so often people use NULL as a flag/invalid value. In that case you could initialize your array to have all NULLs and use that to know the size of the array:
char *array[1024];
memset(array, 0, sizeof(array));
/* .... */
for (int i = 0; i < sizeof(array)/sizeof(char*); i++) {
if (array[i]) {
printf("%s\n", array[i]);
}
}
char *array[1024] = {};
First, that is an array with 1024 char pointers/strings. Those elements can be 0s or plain garbage. If you don't plan to set them all you may want to nullify the array.
For the matter of storing the values and the count you might want to have a look at structs. For example:
typedef struct elem {
int count;
char *value;
} elem;
Then elem.count would be the number and elem.value would be the value accordingly.
And then initialize them in a for loop.
The only really valid way to approach this, is to dynamically grow the array. Allocate the array on the heap, and manage two counts: 1. the count of currently used elements, and 2. the count of elements for which you currently have memory allocated. Something like this:
//the setup
size_t arrayLength = 0, allocatedSize = 8;
int* array = malloc(sizeof(*array) * allocatedSize);
//grow the array -> first check that we have space to add an element
if(arrayLength == allocatedSize) {
array = realloc(array, allocatedSize *= 2);
assert(array);
}
assert(arrayLength < allocatedSize);
//grow the array -> add an element
array[arrayLength++] = ...;
You see, the realloc() call is not too much hassle, but it will protect you from bugs when the requirements change. My experience is that any fixed limit in the code, as insanely large as it may seem to be, will eventually be exceeded, and miserable failure will result. The only safeguard is to use as much memory as needed everywhere.
Related
So I have this struct
#define MAX 128
typedef struct this_struct {
Type items[MAX];
} *SVar;
Lets say we create something like this
SVar first = malloc(sizeof(struct this_struct));
Now when I push values into the array and it fills to the MAX which is 128, I need to dynamically create a new array but I don't know how since the array is inside.
Here are my current thoughts on how I want to do it:
Create a new SVar names "second" with second->items[MAX *2]
free(first)
How can I go about doing this?
The typical way to do that is make your struct contain three values: first, a pointer to an array of variables, and second a count of the currently allocated array size, and in practice, you will need a third item to track the number of array slots you're actually using.
So, with your struct, it would be something like this:
Type *items;
int item_length; /* Number allocated */
int item_count; /* Number in use */
you initially allocate a "batch" of entries, say 100:
first = malloc(sizeof(this_struct));
first->items = malloc(sizeof(Type) * 100);
first->item_length = 100;
first->item_count = 0;
Then you add items one at a time. Simplistically, it's this:
first->items[first->item_count] = new_item;
first->item_count += 1;
But really you need to make sure each time you're not going to overflow the currently-allocated space, so it's really like this:
if (first->item_count == first->item_length) {
first->item_length += 100;
first->items = realloc(first->items, sizeof(Type) * first->item_length);
}
first->items[first->item_count] = new_item;
first->item_count += 1;
You're basically just using slots one at a time as long as your currently allocated space is large enough. Once you've used all the space you've allocated, realloc will either extend the array in place if there is room in the address space, or it will find and allocate a new larger space and move all the existing data to the new spot (and freeing up the old space).
In practice, you should check the return valueon the malloc and realloc calls.
A usual trick is to do something like this:
typedef struct {
int max_items; /* enough memory allocated for so many items */
...
Whatever_type items[1]; /* must be the last member */
} Dyn_array;
...
int n = 127;
Dyn_array *p = malloc(sizeof(Dyn_array) + n*sizeof(p.items[0]);
p->max_items = n + 1;
...
n = 1023;
p = realloc(p, sizeof(Dyn_array) + n*sizeof(p.items[0]);
p->max_items = n + 1;
and so on. The code using the structure performs out-of-bound reads and writes to the items array, which is declared to store one item only. This is OK, however, since C does not do any bounds checking, and the memory allocation policy must guarantee that there is always enough space available for num_items items.
I basically want to store a array of student names, based on a given number. For example, if the user wants to insert 5 names, then the array size will be 5. If the user wants to insert 10 names, then the array size will be 10.
I have a method like this to set a name to a specific element in an array.
void setNames(char *names){
strcpy(name[i], names);
}
Thing is, how do I do array bound checks? I heard that you can only add when the index is -1.
Arrays don't maintain their own size, you have to do that for them. This is part of the reason why vectors are so much easier to deal with, and why everyone will say "wtf, raw arrays? use a vector". An array is just a contiguous chunk of memory, thats it. a vector contains an array, and lets you use it like an array to some extent, but it handles a lot of the housekeeping details for you.
Anyway, if you really want to use a raw array, then you'll need to pass around size information along with it. C strings are a null-terminated array -- just a plain old array, but the last element is \0. This way you can read from it without knowing it's size ahead of time, just don't read past the null character at the end (dragons be there).
EDIT (as the OP indicated he actually wants C):
C answer
What you can do is either create a char array:
char [N][name_length]
where N - number "user wants" (I assume the user will somehow input it into your program), name_length - maximum length the name can have (a C-string, i.e. null-terminated string).
or create an array of your own structs (each holding a separate name and maybe some other information).
C++ answer
A typical way to do this in C++ is by using std::vector<std::string> (assuming you only want to store names, as std::string).
You then add new elements using using push_back() function. And, as vector is implemented as a dynamic array in C++, you won't have to do bound checking.
C code needs to keep track of the array size in another variable.
typedef struct {
char **name;
size_t n;
} Names_T;
void Names_Set(Names_T *names, size_t index, const char *name) {
// See if it is a special value and then append to the array
if (index == (size_t) -1) {
index = names->n;
}
if (index >= names->n) {
size_t newsize = index + 1;
// OOM error handling omitted
names->name = realloc(names->name, newsize * sizeof *names->name);
while (names->n < newsize) {
names->name[names->n++] = NULL;
}
}
char *oldname = names->name[index];
names->name[index] = strdup(name);
free(oldname);
}
void Names_Delete(Names_T *names) {
while (names->n > 0) {
names->n--;
free(&names->name[names->n]);
names->name[names->n] = NULL;
}
free(names->name);
names->name = NULL;
}
int main(void) {
Names_T names = { NULL, 0 };
Names_Set(&names, 3, "Sam"); // set array element 3
Names_Set(&names, (size_t) -1, "Thers"); // Append to array
Names_Delete(&names);
return 0;
}
When programming in C/C++ (unless using C++11 or newer), you will manipulate arrays as pointers. That means you won't know the size of an array unless you save it. What char str[10] really means is str's address + 10 * sizeof(char). You are directly dealing with memory here.
If you want a high level approach for that, take a look at C++11. std::array and std::vector are there for you. From the documentation, look how std::array is defined:
template <
class T,
std::size_t N
> struct array;
It means it stores its own size and has useful functions as well, such as size(), at(), back() etc.
I more or less have an idea, but I'm not sure if I've even got the right idea and I was hoping maybe I was just missing something obvious. Basically, I have and array of strings (C strings, so basically an array of pointers to character arrays) like so:
char **words;
Which I don't know how many words I'll have in the end. As I parse the string, I want to be able to resize the array, add a pointer to the word, and move on to the next word then repeat.
The only way I can think of is to maybe start with a reasonable number and realloc every time I hit the end of the array, but I'm not entirely sure that works. Like I want to be able to access words[0], words[1], etc. If I had char **words[10] and called
realloc(words, n+4) //assuming this is correct since pointers are 4 bytes
once I hit the end of the array, if I did words[11] = new word, is that even valid?
Keep track of your array size:
size_t arr_size = 10;
And give it an initial chunk of memory:
char **words = malloc( arr_size * sizeof(char*) );
Once you have filled all positions, you may want to double the array size:
size_t tailIdx = 0;
while( ... ) {
if( tailIdx >= arr_size ) {
char **newWords;
arr_size *= 2;
newWords = realloc(words, arr_size * sizeof(char*) );
if( newWords == NULL ) { some_error() };
words = newWords;
}
words[tailIdx++] = get_next_word();
}
...
free(words);
That approach is fine ,although you may want to do realloc(words, n * 2) instead. calling realloc and malloc is expensive so you want to have to reallocate as little as possible and this means you can go for longer without reallocating (and possibly copying data). This is how most buffers are implemented to amortize allocation and copy costs. So just double the size of your buffer every time you run out of space.
You are probably going to want to allocate multiple blocks of memory. One for words, which will contain the array of pointers. And then another block for each word, which will be pointed to by elements in the words array.
Adding elements then involves realloc()ing the words array and then allocating new memory blocks for each new word.
Be careful how you write your clean up code. You'll need to be sure to free up all those blocks.
i have a 2D array of size 5428x5428 size.and it is a symmetric array. but while compiling it gives me an error saying that array size too large. can anyone provide me a way?
This array is to large for program stack memory - thats your error.
int main()
{
double arr[5428][5428]; // 8bytes*5428*5428 = 224MB
// ...
// use arr[y][x]
// ...
// no memory freeing needed
}
Use dynamic array allocation:
int main()
{
int i;
double ** arr;
arr = (double**)malloc(sizeof(double*)*5428);
for (i = 0; i < 5428; i++)
arr[i] = (double*)malloc(sizeof(double)*5428);
// ...
// use arr[y][x]
// ...
for (i = 0; i < 5428; i++)
free(arr[i]);
free(arr);
}
Or allocate plain array of size MxN and use ptr[y*width+x]
int main()
{
double * arr;
arr = (double*)malloc(sizeof(double)*5428*5428);
// ...
// use arr[y*5428 + x]
// ...
free(arr);
}
Or use combined method:
int main()
{
int i;
double * arr[5428]; // sizeof(double*)*5428 = 20Kb of stack for x86
for(i = 0; i < 5428; i++)
arr[i] = (double)malloc(sizeof(double)*5428);
// ...
// use arr[y][x]
// ...
for(i = 0; i < 5428; i++)
free(arr[i]);
}
When arrays get large, there are a number of solutions. The one that is good for you depends heavily on what you are actually doing.
I'll list a few to get you thinking:
Buy more memory.
Move your array from the stack to the heap.
The stack has tighter size limitations than the heap.
Simulate portions of the array (you say yours is symmetric, so just under 1/2 of the data is redundant).
In your case, the array is symmetric, so instead of using an array, use a "simulated array"
int getArray(array, col, row);
void setArray(array, col, row, value);
where array is a data structure tha only holds the lower left half and the diagonal. The getArray(..) then determines if the column is greater than the row, and if it is, it returns (note the reversed entries getArray(array, row, col); This leverages the symmetric property of the array without the need to actually hold both symmetric sides.
Simulate the array using a list (or tree or hash table) of "only the value holding items"
This works very well for sparse arrays, as you no longer need to allocate memory to hold large numbers of zero (or empty) values. In the event that someone "looks up" a non-set value, your code "discovers" no value set for that entry, and then returns the "zero" or empty value without it actually being stored in your array.
Again without more details, it is hard to know what kind of solution is the best approach.
When you create local variables, they go on the stack, which is of limited size. You're blowing through that limit.
You want your array to go on the heap, which is all the virtual memory your system has, i.e. gigs and gigs on a modern system. There are two ways to manage that. One is to dynamically allocate the array as in k06a's answer; use malloc() or your platform-specific allocator function (e.g. GlobalAlloc() on Windows) . The second is to declare the array as a global or module static variable, outside of any function.
Using a global or static has the disadvantage that this memory will be allocated for the entire lifetime of your program. Also, pretty much everybody hates globals on principle. On the other hand, you can use the two-dimensional array syntax, "array[x][y]" and the like, to access array elements... easier than doing array[x + y * width], plus you don't have to remember whether you're supposed to be doing "x + y * width" or "x * height + y" .
Ok, this is a C programming homework question. But I'm truly stuck.
I ask the user to input words, and then I insert the input into an array, but I can't have any control over the number of words the user types.
I guess what I'm asking is how do you declare a an array in C without declaring its length and without asking the user what the length should be.
I know this has something to do with malloc, but if you could give me some examples of how to do this, I would really appreciate it.
You can malloc a block of memory large enough to hold a certain number of array items.
Then, before you exceed that number, you can use realloc to make the memory block bigger.
Here's a bit of C code that shows this in action, reallocating an integer array whenever it's too small to hold the next integer.
#include <stdio.h>
#include <stdlib.h>
int main (void) {
int *xyzzy = NULL; // Initially NULL so first realloc is a malloc.
int currsz = 0; // Current capacity.
int i;
// Add ten integers.
for (i = 0; i < 10; i++) {
// If this one will exceed capacity.
if (i >= currsz) {
// Increase capacity by four and re-allocate.
currsz += 4;
xyzzy = realloc (xyzzy, sizeof(int) * currsz);
// Should really check for failure here.
}
// Store number.
xyzzy[i] = 100 + i;
}
// Output capacity and values.
printf ("CurrSz = %d, values =", currsz);
for (i = 0; i < 10; i++) {
printf (" %d", xyzzy[i]);
}
printf ("\n");
return 0;
}
You can realloc it every time like:
int size = 0;
char **array = malloc(0);
while(/* something */)
{
char *string = // get input
size++;
array = realloc(array, size * sizeof(char*));
array[size - 1] = string;
}
Or in chunks if you care about speed.
Yes, you want malloc. Checkout this tut.
http://www.cprogramming.com/tutorial/dynamic_memory_allocation.html
This site is good in general for learning.
Here is an example of using realloc, it is basically exactly what you are asking to do.
http://www.cplusplus.com/reference/clibrary/cstdlib/realloc/
0) obviously you will need multiple buffers, so you will need a list like structure: perhaps a record with char array 100 chars and a pointer to next structure
1) You need to capture the words char by char and store them in your buffer
2) once the buffer is full you allocate another record, chain it with the previous one and keep going until you are out of mem or the process is over.
That should be better performance than realloc function. I believe malloc is trying to give contious block of memory. Therefore the list like structure will be faster and work better.