1

Consider this simple program in Python:

n=int(input("enter your lower limit"))
m=int(input("enter your higher limit"))
list=[]
x=n
while x<=m:
    if (x%2==0):
        list.append(x)
    x+=1
print("the even numbers in your range are:",end="")
print(len(list))

Here I can initially declare the elements of list to nothing and keep inserting a result in it, the range of which completely depends on user. And then I can check the length of that list therefore how many elements fulfilled my conditions between the user's range. So it gets easy in Python!

But in C, I must initially declare the number of elements of an array! I can declare it to a random large number and then keep inserting a result. And then find out the ultimate result (how many elements fulfilled my conditions between the user's range) by checking how many elements are there before the character \0. But it still wastes a lot of memory and keeps garbage in the unused elements which may cause problem in bigger programs!

Well! I know a little about malloc(). But I have to declare the size here too! Though I can free the memory later which reduces pressure in bigger programs but I really want to know if there exists any straightforward process in C like Python?

sashkello
  • 17,306
  • 24
  • 81
  • 109
Nasif Imtiaz Ohi
  • 1,563
  • 5
  • 24
  • 45
  • 3
    There's `realloc`, and you can implement linked-lists or other such "high-level" data structures. But that's about it, nothing in standard C like a vector. – Mat Jul 15 '12 at 14:48
  • 1
    In this instance you know `m`, `n` and that you're going to append in 50% of the cases so it's trivial to compute how big the list needs to be in advance. Why not just do that for malloc or array size? Even if you don't know that you're going to append for 50% you can still compute an upper bound on the number of insertions. – Flexo Jul 15 '12 at 14:48
  • well.. this was just an example... if i don't know the size in other cases, what can i do that was my question !! – Nasif Imtiaz Ohi Jul 15 '12 at 14:52
  • @NasifImtiazOhi - the point was that "don't know the size" is quite rare and "don't know anything about it at all" is even less likely - the better solution is to use the information available to you whenever possible. You can do two passes quite cheaply for example, one to figure out the size and the other to store it once the size is known. – Flexo Jul 15 '12 at 14:53

5 Answers5

7

You need a dynamic data set, such as a dynamically allocated array. You can use malloc or calloc to create the initial array, and realloc to change its size. Beware to test for success, though:

Foo * array = calloc(25, sizeof(Foo));         // space for 25 Foo's, zeroed out
// test for "array != NULL"                    // "25" can be a dynamic value

// use array[0], array[1], ..., array[24]


Foo * tmp = realloc(array, 250 * sizeof(Foo)); // extend to 250 elements
if (tmp) { array = tmp; }
else     { /* error! */ }

// use ... array[249]


free(array);                                   // clean up

Alternatively, you can implement any other dynamic data structure, such as a linked list or a tree, and allocate/free the space for each element (each node) separately and keep track of them somehow. A contiguous array is only the simplest and most straight-forward dynamic data structure, but it is suitable for many scenarios.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Umm... `array = tmp` will not copy the data of the old array. You'd need to do something like `for(i=0; i<25; i++) { tmp[i] = array[i]; }` – Dubslow Jul 15 '12 at 17:44
  • @Dubslow: `array = tmp` is a pointer assignment, deliberately. – Kerrek SB Jul 15 '12 at 19:11
  • That's my point. Doing that will lose you all your data in array (and create a memory leak), surely not what anybody wants. – Dubslow Jul 15 '12 at 22:53
3

You could use Linked List, or you could resize the array, so you can allow it to dynamically grow. Just a basic idea:

#include<stdlib.h>
#include<stdio.h>

struct list_el {
   int val;
   struct list_el * next;
};

typedef struct list_el item;

void main() {
   item * curr, * head;
   int i;

   head = NULL;

   for(i=1;i<=10;i++) {
      curr = (item *)malloc(sizeof(item));
      curr->val = i;
      curr->next  = head;
      head = curr;
   }

   curr = head;
   item * temp;
   while(curr) {
      temp = curr->next;
      printf("%d\n", curr->val);
      free(curr);
      curr = temp;
   }
}

If you want to use arrays, use realloc.

cybertextron
  • 10,547
  • 28
  • 104
  • 208
2

This is how the C works. You have to control manually your memory consumption, allocation, deallocation and so on.

For your case you could:

  1. Use realloc. It will reallocate your array, adding more memory to it and copying contents of it.
  2. Use some external library, like http://bstring.sourceforge.net/ or something, that will hide the complexity of dynamic strings/arrays etc
  3. Use some memory management library, that will manage your own pools, so memory consumption of your application (visible to the system) will be constant, but inside of your app you'll be able to flexibly manage your variables and arrays
  4. Switch to C++ and use STL containers.
akashihi
  • 917
  • 2
  • 9
  • 19
1

You can use realloc to dynamically grow an "array" (block of memory) that you have previously allocated with malloc. The old content of the array will be preserved.

See http://en.cppreference.com/w/c/memory/realloc

Michael
  • 57,169
  • 9
  • 80
  • 125
  • 2
    `realloc` is surprisingly hard to use correctly and probably best avoided, especially by new programmers. (http://stackoverflow.com/q/9071566/168175) – Flexo Jul 15 '12 at 14:50
0

You can try to check about dynamic array, which basically only store an array of pointers which point to your target items. Every time you wanna extend the array, you actually just realloc this pointer array and refresh the pointers.

Wang
  • 7,250
  • 4
  • 35
  • 66