Note that there are some explanatory texts on larger screens.

plurals
  1. POHow do I allocate memory and determine array sizes dynamically in C?
    primarykey
    data
    text
    <p>I am trying to teach myself C from a python background. My current mini-problem is trying to do less hard-coding of things like array lengths and allocate memory dynamically based on input. </p> <p>I've written the following program. I was hoping for suggestions from the community for modifying it in the following ways:</p> <p>1.) Make <code>first</code> and <code>last</code> <code>Name</code> elements variable length. Currently their length is hardcoded as <code>MAX_NAME_LENGTH</code>. This will involve both change <code>Name</code>s <code>struct</code>declaration as well as the way I'm assigning values to its elements.</p> <p>2.) Bonus: Figure out some way to progressively add new elements to the <code>name_list</code> array without having to determine its length beforehand. Basically make it an expandable list.</p> <pre><code>/* namelist.c Loads up a list of names from a file to then do something with them. */ #include &lt;stdlib.h&gt; #include &lt;stdio.h&gt; #include &lt;memory.h&gt; #define DATAFILE "name_list.txt" #define DATAFILE_FORMAT "%[^,]%*c%[^\n]%*c" #define MAX_NAME_LENGTH 100 typedef struct { char first[MAX_NAME_LENGTH]; char last[MAX_NAME_LENGTH]; } Name; int main() { FILE *fp = fopen(DATAFILE, "r"); // Get the number of names in DATAFILE at runtime. Name aName; int lc = 0; while ((fscanf(fp, DATAFILE_FORMAT, aName.last, aName.first))!=EOF) lc++; Name *name_list[lc]; // Now actually pull the data out of the file rewind(fp); int n = 0; while ((fscanf(fp, DATAFILE_FORMAT, aName.last, aName.first))!=EOF) { Name *newName = malloc(sizeof(Name)); if (newName == NULL) { puts("Warning: Was not able to allocate memory for ``Name`` ``newName``on the heap."); } memcpy(newName, &amp;aName, sizeof(Name)); name_list[n] = newName; n++; } int i = 1; for (--n; n &gt;= 0; n--, i++) { printf("%d: %s %s\n", i, name_list[n]-&gt;first, name_list[n]-&gt;last); free(name_list[n]); name_list[n] = NULL; } fclose(fp); return 0; } </code></pre> <p>Sample contents of <code>name_list.txt</code>:</p> <pre><code>Washington,George Adams,John Jefferson,Thomas Madison,James </code></pre> <p><strong>Update 1:</strong></p> <p>I've implemented a linked list and some helper functions as @Williham suggested, results are below.</p> <pre><code>#include &lt;stdlib.h&gt; #include &lt;stdio.h&gt; #include &lt;string.h&gt; #define DATAFILE "name_list.txt" #define MAX_NAME_LENGTH 30 #define DATAFILE_FORMAT "%29[^,]%*c%29[^\n]%*c" static const int INPUT_BUFFER_SIZE_DEFAULT = sizeof(char) * MAX_NAME_LENGTH; typedef struct _Name Name; struct _Name { char *first; char *last; Name *next; }; int get_charcount(char *str); Name * create_name_list(char *filename); void print_name_list(Name *name); void free_name_list (Name *name); int main() { // Read a list of names into memory and // return the head of the linked list. Name *head = create_name_list(DATAFILE); // Now do something with all this data. print_name_list(head); // If you love something, let it go. free_name_list(head); head = NULL; return 0; } int get_charcount (char *str) { int input_length = 1; while (str[input_length] != '\0') { input_length++; } return input_length; } Name * create_name_list(char *filename) { FILE *fp = fopen(DATAFILE, "r"); char *first_input_buffer = malloc(INPUT_BUFFER_SIZE_DEFAULT); char *last_input_buffer = malloc(INPUT_BUFFER_SIZE_DEFAULT); Name *firstNamePtr; Name *previousNamePtr; while ((fscanf(fp, DATAFILE_FORMAT, last_input_buffer, first_input_buffer))!=EOF) { Name *newNamePtr = malloc(sizeof(Name)); if (previousNamePtr) { previousNamePtr-&gt;next = newNamePtr; previousNamePtr = newNamePtr; } else { firstNamePtr = previousNamePtr = newNamePtr; } char *temp_buffer = malloc(get_charcount(first_input_buffer)); strcpy(temp_buffer, first_input_buffer); newNamePtr-&gt;first = malloc(get_charcount(first_input_buffer)); strcpy(newNamePtr-&gt;first, temp_buffer); realloc(temp_buffer, get_charcount(last_input_buffer)); strcpy(temp_buffer, last_input_buffer); newNamePtr-&gt;last = malloc(get_charcount(last_input_buffer)); strcpy(newNamePtr-&gt;last, temp_buffer); free(temp_buffer); temp_buffer = NULL; } previousNamePtr-&gt;next = NULL; previousNamePtr = NULL; free(first_input_buffer); free(last_input_buffer); first_input_buffer = NULL; last_input_buffer = NULL; fclose(fp); return firstNamePtr; } void print_name_list (Name *name) { static int first_iteration = 1; if (first_iteration) { printf("\nList of Names\n"); printf("=============\n"); first_iteration--; } printf("%s %s\n",name-&gt;first, name-&gt;last); if (name-&gt;next) print_name_list(name-&gt;next); else printf("\n"); } void free_name_list (Name *name) { if (name-&gt;next) free_name_list(name-&gt;next); free(name-&gt;first); free(name-&gt;last); name-&gt;first = NULL; name-&gt;last = NULL; name-&gt;next = NULL; free(name); name = NULL; } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload