1

I am having a problem trying to use realloc to grab an extra chunk of memory for a struct (as a record structure). I already have one struct set up and "filled in". My problem is that I cannot seem to visualize how to calculate the number of records currently in the preseently used chunk of memory. The idea is that function addRecord() will calculate how many records currently exist and then grab an extra chunk of memory (using realloc) for one more record each time it is called.

Here is my struct:

 typedef struct rec
{
   char recordUsed;
   char firstName[15];
   char lastName[15];
   char phoneNumber[15];
} record;

Now here is the current (offending) code:

unsigned int addRecord(record * theseRecords)
{
   record * tempRecord;

   /* **Problem lies in next line** */
   unsigned int numberOfRecords = sizeof(theseRecords) / sizeof(record);
   
   /* Use the realloc() function to add contiguous memory segments to the *
    * original memory block when a user adds a new phone book entry. */
   tempRecord = (record *) realloc(theseRecords, ++numberOfRecords * sizeof(record));
   if (tempRecord == NULL)   /* If memory not available ... */
   {
      printf("\nERROR! Out of memory!\n");
      return 0;              /* ... exit program */
   }
   
   theseRecords = tempRecord;   /* Capture possible new pointer */
   printf("\n\tAdd Record\n");
   fillRecord(theseRecords);
}

As requested, here is the main() function that calls the addRecord() function.

int main()
{
   record * theRecords;
   char response;
   
   theRecords = createFirstRecord();
   if (theRecords == NULL)    /* If memory not available then ... */
   {
      printf("\nERROR! Out of memory!");
      return 0;               /* ... exit program */
   }
   
   showTopMenu();
   scanf(" %c", &response);
   response = toupper(response);
   
   while (response != 'Q')
   {
      switch (response)
      {
         case 'A': addRecord(theRecords);
                   break;
         case 'E': editRecord(theRecords);
                   break;
      }  /* end switch() */
      
      showTopMenu();
      scanf(" %c", &response);
      response = toupper(response);
   } /* end while() */
   
   return 0;
}

I am aware that the line in which the number of records is calculated is utter rubbish in that it attempts to divide a pointer with an int. My problem is that I just can't seem to "see" how to do this calculation. Specifically, with what do I replace "sizeof(theseRecords)" ?

Stuart

Stuart
  • 121
  • 7
  • 1
    Does this answer your question? [What is array to pointer decay?](https://stackoverflow.com/questions/1461432/what-is-array-to-pointer-decay) – Persixty Sep 06 '22 at 15:48
  • 3
    `sizeof(theseRecords)` is the size of a pointer on you system. – Jabberwocky Sep 06 '22 at 15:48
  • 1
    _"Specifically, with what do I replace "sizeof(theseRecords)"_: you don't, you need to keep track of the number of records yourself. – Jabberwocky Sep 06 '22 at 15:49
  • 1
    Also [edit] and show the code that calls `addRecord`. Then we can possibly give you some more valuable hints. – Jabberwocky Sep 06 '22 at 15:51
  • Hi, As @Jabberwocky says. That division doesn't do what you think it does. A pointer to an array isn't an array and in C some operations on arrays return pointers and the it gets a bit confusing. – Persixty Sep 06 '22 at 15:52
  • You have to keep separate track of the number of records allocated and the number of records used. You should not, in general, increase the number of records allocated by one each time you need a new record. You should think in terms of doubling the number of allocated records when you need more records. And that's why you need the two counters. – Jonathan Leffler Sep 06 '22 at 16:01
  • You [shouldn't really cast the result of `malloc` (or `realloc`)](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc/605858). – Some programmer dude Sep 06 '22 at 16:41
  • Separate your logic, btw. The fill shouldn't be part of the add. The driver of this (some other function, such as `main`, should be invoking a fill-operation on a singel record, and only if successfully obtained, *then* add the record to the sequence. as it stands now, your fill can fail, and you've already pushed the record into the sequence. – WhozCraig Sep 06 '22 at 17:32
  • To all who replied, please accept my apologies for the tardiness of these replies. – Stuart Sep 09 '22 at 10:44
  • 1
    @Persixty: not directly, but it has given me something more to think about, given a bit more clarity to what is happening with arrays and pointers, so cheers! – Stuart Sep 09 '22 at 10:48
  • @Jabberwocky: First, yes, that dawned on me later hence my comment about that line of code being utter rubbish. Second, that was my initial approach but I wondered if there was a more dynamic way of doing this using facilities within C. Thirdly, I have included the calling code as per your request. – Stuart Sep 09 '22 at 10:55
  • @Jonathan Leffler: Why double the number of records allocated each time ? My thinking was that by allocating only one record each time I was trying to conserve a (possibly) scarce resource, i.e. RAM. – Stuart Sep 09 '22 at 11:02
  • @WhozCraig: I hadn't considered that failure case. Thanks for the clarification. That does make better sense. – Stuart Sep 09 '22 at 11:11
  • @Ian Abbott: An oversight on my part. I had already done something similar at the end of the createFirstRecord() function but neglected to set up your suggestion within the addRecord() function. Given the help already provided (please see above) it is clear that I really need to significantly refactor this program. – Stuart Sep 09 '22 at 11:20
  • @gizlu: "It might be good idea use separate struct as record container." I am not quite clear on how to do that. Would I just use a struct field as a pointer to the start of the records and then use array/index notation to sequence through the records ? Again, your suggestions do make better sense. Thanks. – Stuart Sep 09 '22 at 11:27
  • @Stuart It should answer your question. It should explain the line that is the problem `unsigned int numberOfRecords = sizeof(theseRecords) / sizeof(record);`. That line does not do anything like what is intended because of array pointer 'decay'. – Persixty Sep 09 '22 at 15:05

1 Answers1

2

... The idea is that function addRecord() will calculate how many records currently exist...

Better to pass the record count info in and rework function call. The function needs to modify the record count and the pointer to the records. C passes arguments by value, so use pointers to the variables to be modified:

// unsigned int addRecord(record * theseRecords) {
   // unsigned int numberOfRecords = sizeof(theseRecords) / sizeof(record);

// Have caller pass in reference to the number of records
// and a pointer to the pointer to the records.
unsigned int addRecord(unsigned int *numberOfRecords_ptr, record **theseRecords_ptr) 
{
   // tempRecord = (record *) realloc(theseRecords, ++numberOfRecords * sizeof(record));
   record *tempRecord = 
      realloc(*theseRecords_ptr, (*numberOfRecords_ptr + 1) * sizeof *tempRecord);
   if (tempRecord == NULL)   /* If memory not available ... */
   {
      printf("\nERROR! Out of memory!\n");
      return 0;              /* ... exit program */
   }

   *theseRecords_ptr = tempRecord;   /* Capture possible new pointer */
   printf("\n\tAdd Record\n");
   fillRecord(*theseRecords_ptr + *numberOfRecords_ptr);
   ++(*numberOfRecords_ptr);
   
   return *numberOfRecords_ptr;
}
Ian Abbott
  • 15,083
  • 19
  • 33
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • 2
    The `realloc`ed block also needs to be passed back to the caller somehow. – Ian Abbott Sep 06 '22 at 17:02
  • It might be good idea use separate struct as record container. It can store pointer to records (no shit sherlock), count of records, and allocation size. With separate `alloc_size` field, you can make reallocation to occur much less frequently (you probably don't want to do it at each insert, cause it is relatively expensive) – gizlu Sep 06 '22 at 22:52