At the simplest, you'd convert the loop fragment into:
void print_and_destroy(size_t count, SomeType ptr[count])
{
for (size_t i = 0; i < count; i++)
{
printf("\n%s", ptr[i]->name);
printf("%s", ptr[i]->street);
printf("%s", ptr[i]->citystate);
printf("%s", ptr[i]->zip);
free(ptr[i]);
}
free(ptr);
}
The final free is there because the array is now contains no useful pointers (they've all been freed). You could add ptr[i] = NULL;
after the free(ptr[i]);
instead. That indicates that there is no data there any more.
However, as noted in the comments 1 and 2 by SergeyA, and the clumsy but accurate function name, this isn't a good breakdown of the code. You need two functions:
void destroy(size_t count, SomeType ptr[count])
{
for (size_t i = 0; i < count; i++)
{
free(ptr[i]);
ptr[i] = NULL; // Option 1
}
free(ptr); // Option 2
}
You would not use option 1 if you use option 2 (though it would do no actual harm). If you do not use option 2, you should use option 1.
void print(size_t count, const SomeType ptr[count])
{
for (size_t i = 0; i < count; i++)
{
printf("%s, ", ptr[i]->name);
printf("%s, ", ptr[i]->street);
printf("%s, ", ptr[i]->citystate);
printf("%s\n", ptr[i]->zip);
}
}
Note that you probably need space between the fields of the address. You might or might not want one line for name, one line for street address, and one line for city, state and zip code — choose your format to suit. Generally, output newlines at the end of output, not at the beginning unless you want double spacing.
So that would be my separate function.c
file and my header file would look something like …code omitted…
right? How would the function call in the main program look like?
The outline of the header would be:
#ifndef HEADER_H_INCLUDED
#define HEADER_H_INCLUDED
#include <stddef.h> // Smallest header that defines size_t
typedef struct SomeType
{
char name[32];
char street[32];
char citystate[32];
char zip[11]; // Allow for ZIP+4 and terminal null
} SomeType;
extern void print_and_destroy(size_t count, SomeType ptr[count]);
#endif /* HEADER_H_INCLUDED */
Note that the header doesn't include <stdio.h>
; no part of the interface depends on anything that's specific to <stdio.h>
, such as a FILE *
(though <stdio.h>
is one of the headers that defines size_t
). A header should be minimal, but self-contained and idempotent. Not including <stdio.h>
is part of being minimal; including <stddef.h>
is part of being self-contained; and the header guards are the key part of being idempotent. It means you can include the header and not have to worry about whether it has already been included before indirectly or is included again later, indirectly, and you don't have to worry about what other headers have to be included — the header is self-contained and deals with that.
In your main()
, you'd have something like:
enum { MAX_ADDRESSES = 20 };
SomeType *data[MAX_ADDRESSES];
…memory allocation…
…data loading…
print_and_destroy(MAX_ADDRESSES, data);