Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #162473 > unrolled thread
| Started by | Bithov Vinu Student <vinub@calday.co.uk> |
|---|---|
| First post | 2021-08-29 08:34 -0700 |
| Last post | 2021-08-31 04:22 +0200 |
| Articles | 20 on this page of 38 — 14 participants |
Back to article view | Back to comp.lang.c
Freeing a dynamically allocated array of structs within a struct in C Bithov Vinu Student <vinub@calday.co.uk> - 2021-08-29 08:34 -0700
Re: Freeing a dynamically allocated array of structs within a struct in C Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2021-08-29 15:43 +0000
Re: Freeing a dynamically allocated array of structs within a struct in C Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2021-08-29 16:12 +0000
Re: Freeing a dynamically allocated array of structs within a struct in C Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-09-06 05:46 -0700
Re: Freeing a dynamically allocated array of structs within a struct in C Ben Bacarisse <ben.usenet@bsb.me.uk> - 2021-08-29 17:17 +0100
Re: Freeing a dynamically allocated array of structs within a struct in C Bonita Montero <Bonita.Montero@gmail.com> - 2021-08-29 20:01 +0200
Re: Freeing a dynamically allocated array of structs within a struct in C Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2021-08-29 18:21 +0000
Re: Freeing a dynamically allocated array of structs within a struct in C Bonita Montero <Bonita.Montero@gmail.com> - 2021-08-29 20:34 +0200
Re: Freeing a dynamically allocated array of structs within a struct in C Bonita Montero <Bonita.Montero@gmail.com> - 2021-08-30 09:01 +0200
Re: Freeing a dynamically allocated array of structs within a struct in C Robert Latest <boblatest@yahoo.com> - 2021-08-31 05:44 +0000
Re: Freeing a dynamically allocated array of structs within a struct in C Kaz Kylheku <563-365-8930@kylheku.com> - 2021-08-31 07:50 +0000
Re: Freeing a dynamically allocated array of structs within a struct in C Bonita Montero <Bonita.Montero@gmail.com> - 2021-08-31 10:59 +0200
Re: Freeing a dynamically allocated array of structs within a struct in C Bonita Montero <Bonita.Montero@gmail.com> - 2021-08-30 09:45 +0200
Re: Freeing a dynamically allocated array of structs within a struct in C Bonita Montero <Bonita.Montero@gmail.com> - 2021-08-30 10:15 +0200
Re: Freeing a dynamically allocated array of structs within a struct in C Kaz Kylheku <563-365-8930@kylheku.com> - 2021-08-29 18:14 +0000
Re: Freeing a dynamically allocated array of structs within a struct in C Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2021-08-29 18:18 +0000
Re: Freeing a dynamically allocated array of structs within a struct in C Barry Schwarz <schwarzb@delq.com> - 2021-08-29 11:44 -0700
Re: Freeing a dynamically allocated array of structs within a struct in C Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2021-08-29 19:04 +0000
Re: Freeing a dynamically allocated array of structs within a struct in C Barry Schwarz <schwarzb@delq.com> - 2021-08-29 14:15 -0700
Re: Freeing a dynamically allocated array of structs within a struct in C scott@slp53.sl.home (Scott Lurndal) - 2021-08-29 21:19 +0000
Re: Freeing a dynamically allocated array of structs within a struct in C Barry Schwarz <schwarzb@delq.com> - 2021-08-29 18:14 -0700
Re: Freeing a dynamically allocated array of structs within a struct in C Bonita Montero <Bonita.Montero@gmail.com> - 2021-08-30 18:27 +0200
Re: Freeing a dynamically allocated array of structs within a struct in C Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2021-08-30 16:17 +0000
Re: Freeing a dynamically allocated array of structs within a struct in C James Kuyper <jameskuyper@alumni.caltech.edu> - 2021-08-30 14:14 -0400
Re: Freeing a dynamically allocated array of structs within a struct in C Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-08-30 11:39 -0700
Re: Freeing a dynamically allocated array of structs within a struct in C James Kuyper <jameskuyper@alumni.caltech.edu> - 2021-08-31 10:08 -0400
Re: Freeing a dynamically allocated array of structs within a struct in C Kaz Kylheku <563-365-8930@kylheku.com> - 2021-09-01 04:40 +0000
Re: Freeing a dynamically allocated array of structs within a struct in C Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-09-01 00:57 -0700
Re: Freeing a dynamically allocated array of structs within a struct in C Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2021-08-30 19:16 +0000
Re: Freeing a dynamically allocated array of structs within a struct in C Manfred <noname@add.invalid> - 2021-08-30 21:49 +0200
Re: Freeing a dynamically allocated array of structs within a struct in C "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2021-08-30 12:49 -0700
Re: Freeing a dynamically allocated array of structs within a struct in C scott@slp53.sl.home (Scott Lurndal) - 2021-08-30 22:31 +0000
Re: Freeing a dynamically allocated array of structs within a struct in C Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-09-30 07:04 -0700
Re: Freeing a dynamically allocated array of structs within a struct in C Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-08-29 15:38 -0700
Re: Freeing a dynamically allocated array of structs within a struct in C Manfred <noname@add.invalid> - 2021-08-30 14:21 +0200
Re: Freeing a dynamically allocated array of structs within a struct in C Bonita Montero <Bonita.Montero@gmail.com> - 2021-08-30 18:29 +0200
Re: Freeing a dynamically allocated array of structs within a struct in C Bart <bc@freeuk.com> - 2021-08-30 18:30 +0100
Re: Freeing a dynamically allocated array of structs within a struct in C Bonita Montero <Bonita.Montero@gmail.com> - 2021-08-31 04:22 +0200
Page 1 of 2 [1] 2 Next page →
| From | Bithov Vinu Student <vinub@calday.co.uk> |
|---|---|
| Date | 2021-08-29 08:34 -0700 |
| Subject | Freeing a dynamically allocated array of structs within a struct in C |
| Message-ID | <1348a974-54cd-47cf-bf40-7034feaa1f78n@googlegroups.com> |
Hi,
I have the following definition:
```
typedef struct {
char* entry_key;
char* entry_value;
} deck_entry;
```
And the following function to parse a string into a deck_entry:
```
deck_entry* parse_deck_entry(char* to_parse) {
char* string_to_parse = strdup(to_parse);
char* a = strsep(&string_to_parse, ": ");
char* b = strsep(&string_to_parse, "\n");
return make_deck_entry(a, b);
}
```
With the test code as follows:
```
int main() {
deck_entry* new_deck = parse_deck_entry("Age: 23\n");
free_deck_entry(new_deck);
return 0;
}
```
The program works without segfaulting or anything else, in fact, using a diagnostic function I wrote (print_deck_entry) all the information has been parsed properly with the write formatting, etc. However, running through Valgrind shows:
```
==8494== Memcheck, a memory error detector
==8494== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==8494== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==8494== Command: ./box
==8494==
==8494==
==8494== HEAP SUMMARY:
==8494== in use at exit: 25 bytes in 1 blocks
==8494== total heap usage: 4 allocs, 3 frees, 65 bytes allocated
==8494==
==8494== LEAK SUMMARY:
==8494== definitely lost: 25 bytes in 1 blocks
==8494== indirectly lost: 0 bytes in 0 blocks
==8494== possibly lost: 0 bytes in 0 blocks
==8494== still reachable: 0 bytes in 0 blocks
==8494== suppressed: 0 bytes in 0 blocks
==8494== Rerun with --leak-check=full to see details of leaked memory
==8494==
==8494== For lists of detected and suppressed errors, rerun with: -s
==8494== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
```
Modifying parse_deck_entry to be the following:
```
deck_entry* parse_deck_entry(char* to_parse) {
char* string_to_parse = strdup(to_parse);
char* a = strsep(&string_to_parse, ": ");
char* b = strsep(&string_to_parse, "\n");
deck_entry* tmp = make_deck_entry(a, b);
free(a);
free(b);
free(string_to_parse);
return tmp;
}
```
...will still compile but prints the following when run:
```
free(): invalid pointer
Aborted (core dumped)
```
I can't imagine anything else that could be causing a memory leak, considering parse_deck_entry() is the only function I've written that is being called in the test code. What have I done wrong and what could I do to improve? Stability and memory-safety are pretty huge for what I'm writing, even though I am writing in C (rather than Rust, etc.)
Thanks,
Bithov
--
Student Account
--
Calday Grange Grammar School is a charitable company limited by guarantee
and registered in England and Wales with company number 8332696.
The
Registered Office is at Grammar School Lane, West Kirby, Wirral, CH48 8GG
[toc] | [next] | [standalone]
| From | Lew Pitcher <lew.pitcher@digitalfreehold.ca> |
|---|---|
| Date | 2021-08-29 15:43 +0000 |
| Message-ID | <sgg9us$1vg$1@dont-email.me> |
| In reply to | #162473 |
On Sun, 29 Aug 2021 08:34:56 -0700, Bithov Vinu Student wrote:
> Hi,
>
> I have the following definition:
>
> ```
> typedef struct {
> char* entry_key;
> char* entry_value;
> } deck_entry;
> ```
>
> And the following function to parse a string into a deck_entry:
>
> ```
> deck_entry* parse_deck_entry(char* to_parse) {
> char* string_to_parse = strdup(to_parse);
> char* a = strsep(&string_to_parse, ": ");
> char* b = strsep(&string_to_parse, "\n");
> return make_deck_entry(a, b);
> }
> ```
>
> With the test code as follows:
>
> ```
> int main() {
> deck_entry* new_deck = parse_deck_entry("Age: 23\n");
> free_deck_entry(new_deck);
> return 0;
> }
> ```
>
> The program works without segfaulting or anything else, in fact, using a diagnostic function I wrote (print_deck_entry) all the information has been parsed properly with the write formatting, etc. However, running through Valgrind shows:
>
> ```
> ==8494== Memcheck, a memory error detector
> ==8494== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
> ==8494== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
> ==8494== Command: ./box
> ==8494==
> ==8494==
> ==8494== HEAP SUMMARY:
> ==8494== in use at exit: 25 bytes in 1 blocks
> ==8494== total heap usage: 4 allocs, 3 frees, 65 bytes allocated
> ==8494==
> ==8494== LEAK SUMMARY:
> ==8494== definitely lost: 25 bytes in 1 blocks
> ==8494== indirectly lost: 0 bytes in 0 blocks
> ==8494== possibly lost: 0 bytes in 0 blocks
> ==8494== still reachable: 0 bytes in 0 blocks
> ==8494== suppressed: 0 bytes in 0 blocks
> ==8494== Rerun with --leak-check=full to see details of leaked memory
> ==8494==
> ==8494== For lists of detected and suppressed errors, rerun with: -s
> ==8494== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
> ```
>
> Modifying parse_deck_entry to be the following:
>
> ```
> deck_entry* parse_deck_entry(char* to_parse) {
> char* string_to_parse = strdup(to_parse);
> char* a = strsep(&string_to_parse, ": ");
> char* b = strsep(&string_to_parse, "\n");
> deck_entry* tmp = make_deck_entry(a, b);
> free(a);
> free(b);
> free(string_to_parse);
> return tmp;
> }
> ```
>
> ...will still compile but prints the following when run:
>
> ```
> free(): invalid pointer
> Aborted (core dumped)
> ```
>
> I can't imagine anything else that could be causing a memory leak, considering parse_deck_entry() is the only function I've written that is being called in the test code. What have I done wrong and what could I do to improve? Stability and memory-safety are pretty huge for what I'm writing, even though I am writing in C (rather than Rust, etc.)
Take another look at...
> char* a = strsep(&string_to_parse, ": ");
> char* b = strsep(&string_to_parse, "\n");
and
> free(a);
> free(b);
> free(string_to_parse);
The strsep() function /does not/ allocate new memory for it's results.
Instead, it /modifies/ the contents of the string passed into it, and
returns a pointer to the modified string.
So, as
> char* a = strsep(&string_to_parse, ": ");
> char* b = strsep(&string_to_parse, "\n");
does not allocate memory, you should not
> free(a);
> free(b);
that memory.
--
Lew Pitcher
"In Skills, We Trust"
[toc] | [prev] | [next] | [standalone]
| From | Lew Pitcher <lew.pitcher@digitalfreehold.ca> |
|---|---|
| Date | 2021-08-29 16:12 +0000 |
| Message-ID | <sggbl5$1vg$2@dont-email.me> |
| In reply to | #162474 |
On Sun, 29 Aug 2021 15:43:24 +0000, Lew Pitcher wrote:
> On Sun, 29 Aug 2021 08:34:56 -0700, Bithov Vinu Student wrote:
>
>> Hi,
>>
>> I have the following definition:
>>
>> ```
>> typedef struct {
>> char* entry_key;
>> char* entry_value;
>> } deck_entry;
>> ```
>>
>> And the following function to parse a string into a deck_entry:
>>
>> ```
>> deck_entry* parse_deck_entry(char* to_parse) {
>> char* string_to_parse = strdup(to_parse);
>> char* a = strsep(&string_to_parse, ": ");
>> char* b = strsep(&string_to_parse, "\n");
>> return make_deck_entry(a, b);
>> }
>> ```
>>
>> With the test code as follows:
>>
>> ```
>> int main() {
>> deck_entry* new_deck = parse_deck_entry("Age: 23\n");
>> free_deck_entry(new_deck);
>> return 0;
>> }
>> ```
>>
>> The program works without segfaulting or anything else, in fact, using a diagnostic function I wrote (print_deck_entry) all the information has been parsed properly with the write formatting, etc. However, running through Valgrind shows:
>>
>> ```
>> ==8494== Memcheck, a memory error detector
>> ==8494== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
>> ==8494== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
>> ==8494== Command: ./box
>> ==8494==
>> ==8494==
>> ==8494== HEAP SUMMARY:
>> ==8494== in use at exit: 25 bytes in 1 blocks
>> ==8494== total heap usage: 4 allocs, 3 frees, 65 bytes allocated
>> ==8494==
>> ==8494== LEAK SUMMARY:
>> ==8494== definitely lost: 25 bytes in 1 blocks
>> ==8494== indirectly lost: 0 bytes in 0 blocks
>> ==8494== possibly lost: 0 bytes in 0 blocks
>> ==8494== still reachable: 0 bytes in 0 blocks
>> ==8494== suppressed: 0 bytes in 0 blocks
>> ==8494== Rerun with --leak-check=full to see details of leaked memory
>> ==8494==
>> ==8494== For lists of detected and suppressed errors, rerun with: -s
>> ==8494== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
>> ```
>>
>> Modifying parse_deck_entry to be the following:
>>
>> ```
>> deck_entry* parse_deck_entry(char* to_parse) {
>> char* string_to_parse = strdup(to_parse);
>> char* a = strsep(&string_to_parse, ": ");
>> char* b = strsep(&string_to_parse, "\n");
>> deck_entry* tmp = make_deck_entry(a, b);
>> free(a);
>> free(b);
>> free(string_to_parse);
>> return tmp;
>> }
>> ```
>>
>> ...will still compile but prints the following when run:
>>
>> ```
>> free(): invalid pointer
>> Aborted (core dumped)
>> ```
>>
>> I can't imagine anything else that could be causing a memory leak, considering parse_deck_entry() is the only function I've written that is being called in the test code. What have I done wrong and what could I do to improve? Stability and memory-safety are pretty huge for what I'm writing, even though I am writing in C (rather than Rust, etc.)
>
> Take another look at...
>> char* a = strsep(&string_to_parse, ": ");
>> char* b = strsep(&string_to_parse, "\n");
> and
>> free(a);
>> free(b);
>> free(string_to_parse);
>
> The strsep() function /does not/ allocate new memory for it's results.
> Instead, it /modifies/ the contents of the string passed into it, and
> returns a pointer to the modified string.
>
> So, as
>> char* a = strsep(&string_to_parse, ": ");
>> char* b = strsep(&string_to_parse, "\n");
> does not allocate memory, you should not
>> free(a);
>> free(b);
> that memory.
Note also that strsep() "modifies it's first argument".
This means that, after your first call to strsep(),
>> char* a = strsep(&string_to_parse, ": ");
string_to_parse /no longer/ points to the first byte
of the memory allocated by your call to strdup().
This will make
>> free(string_to_parse);
problematic as well.
--
Lew Pitcher
"In Skills, We Trust"
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2021-09-06 05:46 -0700 |
| Message-ID | <86pmtlvpky.fsf@linuxsc.com> |
| In reply to | #162475 |
Lew Pitcher <lew.pitcher@digitalfreehold.ca> writes: > On Sun, 29 Aug 2021 15:43:24 +0000, Lew Pitcher wrote: [...] >> The strsep() function /does not/ allocate new memory for it's >> results. [...] > Note also that strsep() "modifies it's first argument". The word "it's" is a contraction for "it is". The possessive form of the word "it" is "its", with no apostrophe. It may help to remember that the same rule applies to all personal pronouns: an apostrophe always indicates a contraction with "am", "is" or "are" - I am, we are - I'm, we're you are - you're he is, she is, it is, they are - he's, she's, it's, they're and there is never an apostrophe in the possessive form of a personal pronoun - my, our your his, hers, its, their
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2021-08-29 17:17 +0100 |
| Message-ID | <87h7f86x9j.fsf@bsb.me.uk> |
| In reply to | #162473 |
Bithov Vinu Student <vinub@calday.co.uk> writes:
> I have the following definition:
>
> ```
> typedef struct {
> char* entry_key;
> char* entry_value;
> } deck_entry;
> ```
>
> And the following function to parse a string into a deck_entry:
>
> ```
> deck_entry* parse_deck_entry(char* to_parse) {
> char* string_to_parse = strdup(to_parse);
> char* a = strsep(&string_to_parse, ": ");
> char* b = strsep(&string_to_parse, "\n");
> return make_deck_entry(a, b);
> }
> ```
>
> With the test code as follows:
>
> ```
> int main() {
> deck_entry* new_deck = parse_deck_entry("Age: 23\n");
> free_deck_entry(new_deck);
> return 0;
> }
> ```
>
> The program works without segfaulting or anything else, in fact, using
> a diagnostic function I wrote (print_deck_entry) all the information
> has been parsed properly with the write formatting, etc. However,
> running through Valgrind shows:
>
> ```
> ==8494== Memcheck, a memory error detector
> ==8494== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
> ==8494== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
> ==8494== Command: ./box
> ==8494==
> ==8494==
> ==8494== HEAP SUMMARY:
> ==8494== in use at exit: 25 bytes in 1 blocks
> ==8494== total heap usage: 4 allocs, 3 frees, 65 bytes allocated
> ==8494==
> ==8494== LEAK SUMMARY:
> ==8494== definitely lost: 25 bytes in 1 blocks
> ==8494== indirectly lost: 0 bytes in 0 blocks
> ==8494== possibly lost: 0 bytes in 0 blocks
> ==8494== still reachable: 0 bytes in 0 blocks
> ==8494== suppressed: 0 bytes in 0 blocks
> ==8494== Rerun with --leak-check=full to see details of leaked memory
> ==8494==
> ==8494== For lists of detected and suppressed errors, rerun with: -s
> ==8494== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
> ```
>
> Modifying parse_deck_entry to be the following:
>
> ```
> deck_entry* parse_deck_entry(char* to_parse) {
> char* string_to_parse = strdup(to_parse);
> char* a = strsep(&string_to_parse, ": ");
> char* b = strsep(&string_to_parse, "\n");
> deck_entry* tmp = make_deck_entry(a, b);
> free(a);
> free(b);
> free(string_to_parse);
> return tmp;
> }
> ```
First off (and I know it's not really the answer to your question), you
can only pass to free a pointer returned by malloc (or calloc or
realloc), and you must free that pointer only once.
strdup (not a standard C function) returns a pointer from malloc and 'a'
probably holds an identical pointer value to 'string_to_parse' so this
code has two errors: the malloc'd storage is freed twice, and a pointer
that was not returned by malloc (the value in 'b') is passed to free.
> ...will still compile but prints the following when run:
>
> ```
> free(): invalid pointer
> Aborted (core dumped)
> ```
>
> I can't imagine anything else that could be causing a memory leak,
> considering parse_deck_entry() is the only function I've written that
> is being called in the test code. What have I done wrong and what
> could I do to improve?
The leak is indeed the 9 bytes allocated to the copy of "Age: 23\n" and
the 16 bytes used by the allocated struct.
The real problem is that you must free this storage only when it is not
needed. If you free it in parse_deck_entry you can't use the entry for
anything -- the storage has already gone.
Most programs free the storage after they have finished working with
it. For many programs, that is just before main returns, and there are
many people who will advise you not to both if that is your situation as
every sensible OS will free the storage when you program finished.
But I am no one of them! Programs can become sub-programs, and making
sure that you free all allocated storage is not hard and will make
re-using part of this program on others much less error prone.
> Stability and memory-safety are pretty huge for what I'm writing, even
> though I am writing in C (rather than Rust, etc.)
Out of interest, why did you choose C?
(And kudos for posting a clear question with all the data needed to give
a reasonable stab as a reply. It's less common than you might think.)
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2021-08-29 20:01 +0200 |
| Message-ID | <sggi2c$jkm$1@dont-email.me> |
| In reply to | #162473 |
Use a proper language:
#include <memory>
#include <string>
using namespace std;
struct deck_entry
{
string key,
value;
};
using up_de_t = unique_ptr<deck_entry>;
up_de_t parse_deck_entry( string const &parse )
{
size_t delimiterBegin = parse.find( ": " );
if( delimiterBegin == string::npos )
return up_de_t();
up_de_t de = make_unique<deck_entry>();
de->key = string( parse.begin(), parse.begin() + delimiterBegin );
de->value = string( parse.begin() + (delimiterBegin + 2), parse.end() );
return de;
}
Full saftety if an allocation fails, automatic deallocation of
all allocated memory.
[toc] | [prev] | [next] | [standalone]
| From | Lew Pitcher <lew.pitcher@digitalfreehold.ca> |
|---|---|
| Date | 2021-08-29 18:21 +0000 |
| Message-ID | <sggj78$1vg$4@dont-email.me> |
| In reply to | #162477 |
On Sun, 29 Aug 2021 20:01:48 +0200, Bonita Montero wrote: > Use a proper language: > > #include <memory> > #include <string> > > using namespace std; Bonita, Regardless of your opinions on what constitutes a "proper" language, this is comp.lang.c, and we do /not/ accept C++ (or COBOL or Fortran or Rust or Perl) solutions as answers to C questions. Please take your C anti-advocacy elsewhere. -- Lew Pitcher "In Skills, We Trust"
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2021-08-29 20:34 +0200 |
| Message-ID | <sggjv7$1sh$1@dont-email.me> |
| In reply to | #162480 |
Am 29.08.2021 um 20:21 schrieb Lew Pitcher: > On Sun, 29 Aug 2021 20:01:48 +0200, Bonita Montero wrote: > >> Use a proper language: >> >> #include <memory> >> #include <string> >> >> using namespace std; > > Bonita, > > Regardless of your opinions on what constitutes a "proper" language, > this is comp.lang.c, and we do /not/ accept C++ (or COBOL or Fortran > or Rust or Perl) solutions as answers to C questions. > > Please take your C anti-advocacy elsewhere. Maybe he sees that he'll better learn a different language. Maybe not even C++, but just a better one.
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2021-08-30 09:01 +0200 |
| Message-ID | <sghvo3$jra$1@dont-email.me> |
| In reply to | #162477 |
Am 29.08.2021 um 20:01 schrieb Bonita Montero:
> Use a proper language:
>
> #include <memory>
> #include <string>
>
> using namespace std;
>
> struct deck_entry
> {
> string key,
> value;
> };
>
> using up_de_t = unique_ptr<deck_entry>;
>
> up_de_t parse_deck_entry( string const &parse )
> {
> size_t delimiterBegin = parse.find( ": " );
> if( delimiterBegin == string::npos )
> return up_de_t();
> up_de_t de = make_unique<deck_entry>();
> de->key = string( parse.begin(), parse.begin() + delimiterBegin );
> de->value = string( parse.begin() + (delimiterBegin + 2),
> parse.end() );
> return de;
> }
And now this ugly C-pendant:
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
typedef struct deck_entry
{
char *key,
*value;
} deck_entry;
deck_entry *parseDeckEntry( char const *parse )
{
size_t len = strlen( parse );
char const *delimiter = strstr( parse, ": " );
if( !delimiter || delimiter == parse || delimiter == parse + len - 2 )
return NULL;
deck_entry *de = NULL;
if( !(de = malloc( sizeof(deck_entry) )) )
return NULL;
char *key, *value;
if( !(de->key = malloc( delimiter - parse + 1 )) )
goto undoDE;
if( !(de->value = malloc( len - (delimiter - parse + 2) + 1 )) )
goto undoKey;
strncpy( de->key, parse, delimiter - parse );
strcpy( de->value, delimiter + 2 );
return de;
undoKey:
free( de->key );
undoDE:
free( de );
return NULL;
}
[toc] | [prev] | [next] | [standalone]
| From | Robert Latest <boblatest@yahoo.com> |
|---|---|
| Date | 2021-08-31 05:44 +0000 |
| Message-ID | <ip5ttkFrdbaU2@mid.individual.net> |
| In reply to | #162490 |
Bonita Montero wrote: > And now this ugly C-pendant: What is your interest in comp.lang.c?
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <563-365-8930@kylheku.com> |
|---|---|
| Date | 2021-08-31 07:50 +0000 |
| Message-ID | <20210831003134.197@kylheku.com> |
| In reply to | #162490 |
On 2021-08-30, Bonita Montero <Bonita.Montero@gmail.com> wrote:
> Am 29.08.2021 um 20:01 schrieb Bonita Montero:
>> Use a proper language:
>>
>> #include <memory>
>> #include <string>
>>
>> using namespace std;
>>
>> struct deck_entry
>> {
>> string key,
>> value;
>> };
>>
>> using up_de_t = unique_ptr<deck_entry>;
>>
>> up_de_t parse_deck_entry( string const &parse )
>> {
>> size_t delimiterBegin = parse.find( ": " );
>> if( delimiterBegin == string::npos )
>> return up_de_t();
>> up_de_t de = make_unique<deck_entry>();
>> de->key = string( parse.begin(), parse.begin() + delimiterBegin );
>> de->value = string( parse.begin() + (delimiterBegin + 2),
>> parse.end() );
>> return de;
>> }
>
> And now this ugly C-pendant:
>
> #include <stddef.h>
> #include <string.h>
> #include <stdlib.h>
>
> typedef struct deck_entry
> {
> char *key,
> *value;
> } deck_entry;
>
> deck_entry *parseDeckEntry( char const *parse )
> {
> size_t len = strlen( parse );
> char const *delimiter = strstr( parse, ": " );
> if( !delimiter || delimiter == parse || delimiter == parse + len - 2 )
> return NULL;
> deck_entry *de = NULL;
> if( !(de = malloc( sizeof(deck_entry) )) )
> return NULL;
> char *key, *value;
> if( !(de->key = malloc( delimiter - parse + 1 )) )
> goto undoDE;
> if( !(de->value = malloc( len - (delimiter - parse + 2) + 1 )) )
> goto undoKey;
> strncpy( de->key, parse, delimiter - parse );
> strcpy( de->value, delimiter + 2 );
> return de;
> undoKey:
> free( de->key );
> undoDE:
> free( de );
> return NULL;
> }
That's fine, but when you're dealing with manual resource management,
a structure like the following structure is nice:
deck_entry *parseDeckEntry(char const *parse)
{
size_t len = strlen(parse);
char const *delimiter = strstr(parse, ": ");
if (!delimiter || delimiter == parse || delimiter == parse + len - 2)
return NULL;
deck_entry *de = malloc(sizeof *de);
char *key = malloc(delimiter - parse + 1);
char *value = malloc(len - (delimiter - parse + 2) + 1);
if (de && key && value) {
strncpy(key, parse, delimiter - parse);
strcpy(value, delimiter + 2);
de->key = key;
de->value = value;
return de;
}
free(value);
free(key);
free(de);
return NULL;
}
}
--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2021-08-31 10:59 +0200 |
| Message-ID | <sgkr22$ida$1@dont-email.me> |
| In reply to | #162510 |
Am 31.08.2021 um 09:50 schrieb Kaz Kylheku:
> On 2021-08-30, Bonita Montero <Bonita.Montero@gmail.com> wrote:
>> Am 29.08.2021 um 20:01 schrieb Bonita Montero:
>>> Use a proper language:
>>>
>>> #include <memory>
>>> #include <string>
>>>
>>> using namespace std;
>>>
>>> struct deck_entry
>>> {
>>> string key,
>>> value;
>>> };
>>>
>>> using up_de_t = unique_ptr<deck_entry>;
>>>
>>> up_de_t parse_deck_entry( string const &parse )
>>> {
>>> size_t delimiterBegin = parse.find( ": " );
>>> if( delimiterBegin == string::npos )
>>> return up_de_t();
>>> up_de_t de = make_unique<deck_entry>();
>>> de->key = string( parse.begin(), parse.begin() + delimiterBegin );
>>> de->value = string( parse.begin() + (delimiterBegin + 2),
>>> parse.end() );
>>> return de;
>>> }
>>
>> And now this ugly C-pendant:
>>
>> #include <stddef.h>
>> #include <string.h>
>> #include <stdlib.h>
>>
>> typedef struct deck_entry
>> {
>> char *key,
>> *value;
>> } deck_entry;
>>
>> deck_entry *parseDeckEntry( char const *parse )
>> {
>> size_t len = strlen( parse );
>> char const *delimiter = strstr( parse, ": " );
>> if( !delimiter || delimiter == parse || delimiter == parse + len - 2 )
>> return NULL;
>> deck_entry *de = NULL;
>> if( !(de = malloc( sizeof(deck_entry) )) )
>> return NULL;
>> char *key, *value;
>> if( !(de->key = malloc( delimiter - parse + 1 )) )
>> goto undoDE;
>> if( !(de->value = malloc( len - (delimiter - parse + 2) + 1 )) )
>> goto undoKey;
>> strncpy( de->key, parse, delimiter - parse );
>> strcpy( de->value, delimiter + 2 );
>> return de;
>> undoKey:
>> free( de->key );
>> undoDE:
>> free( de );
>> return NULL;
>> }
>
> That's fine, but when you're dealing with manual resource management,
> a structure like the following structure is nice:
>
> deck_entry *parseDeckEntry(char const *parse)
> {
> size_t len = strlen(parse);
> char const *delimiter = strstr(parse, ": ");
>
> if (!delimiter || delimiter == parse || delimiter == parse + len - 2)
> return NULL;
>
> deck_entry *de = malloc(sizeof *de);
> char *key = malloc(delimiter - parse + 1);
> char *value = malloc(len - (delimiter - parse + 2) + 1);
>
> if (de && key && value) {
> strncpy(key, parse, delimiter - parse);
> strcpy(value, delimiter + 2);
> de->key = key;
> de->value = value;
> return de;
> }
>
> free(value);
> free(key);
> free(de);
>
> return NULL;
> }
> }
I "prefer" the goto-way like the people in the Linux-kernel do.
It only deallocates the resources already allocated.
But nevertheless programming this with manual resource management
is a mess.
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2021-08-30 09:45 +0200 |
| Message-ID | <sgi2an$2m6$1@dont-email.me> |
| In reply to | #162477 |
Am 29.08.2021 um 20:01 schrieb Bonita Montero:
> Use a proper language:
>
> #include <memory>
> #include <string>
>
> using namespace std;
>
> struct deck_entry
> {
> string key,
> value;
> };
>
> using up_de_t = unique_ptr<deck_entry>;
>
> up_de_t parse_deck_entry( string const &parse )
> {
> size_t delimiterBegin = parse.find( ": " );
> if( delimiterBegin == string::npos )
> return up_de_t();
> up_de_t de = make_unique<deck_entry>();
> de->key = string( parse.begin(), parse.begin() + delimiterBegin );
> de->value = string( parse.begin() + (delimiterBegin + 2),
> parse.end() );
> return de;
> }
>
> Full saftety if an allocation fails, automatic deallocation of
> all allocated memory.
And now more elegance and performance:
#include <memory>
#include <string>
using namespace std;
struct deck_entry
{
string key,
value;
deck_entry( string &&key, string &&value ) :
key( key ),
value( value )
{
}
};
using up_de_t = unique_ptr<deck_entry>;
up_de_t parse_deck_entry( string const &parse )
{
size_t delimiter = parse.find( ": " );
if( delimiter == string::npos || !delimiter || delimiter ==
parse.size() - 2 )
return up_de_t();
return make_unique<deck_entry>( string( parse.begin(), parse.begin() +
delimiter ),
string( parse.begin() + (delimiter +
2), parse.end() ) );
}
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2021-08-30 10:15 +0200 |
| Message-ID | <sgi43m$cil$1@dont-email.me> |
| In reply to | #162491 |
Am 30.08.2021 um 09:45 schrieb Bonita Montero:
> Am 29.08.2021 um 20:01 schrieb Bonita Montero:
>> Use a proper language:
>>
>> #include <memory>
>> #include <string>
>>
>> using namespace std;
>>
>> struct deck_entry
>> {
>> string key,
>> value;
>> };
>>
>> using up_de_t = unique_ptr<deck_entry>;
>>
>> up_de_t parse_deck_entry( string const &parse )
>> {
>> size_t delimiterBegin = parse.find( ": " );
>> if( delimiterBegin == string::npos )
>> return up_de_t();
>> up_de_t de = make_unique<deck_entry>();
>> de->key = string( parse.begin(), parse.begin() +
>> delimiterBegin );
>> de->value = string( parse.begin() + (delimiterBegin + 2),
>> parse.end() );
>> return de;
>> }
>>
>> Full saftety if an allocation fails, automatic deallocation of
>> all allocated memory.
>
> And now more elegance and performance:
>
> #include <memory>
> #include <string>
>
> using namespace std;
>
> struct deck_entry
> {
> string key,
> value;
> deck_entry( string &&key, string &&value ) :
> key( key ),
> value( value )
key( move( key ) ),
value( move( value ) )
> {
> }
> };
>
> using up_de_t = unique_ptr<deck_entry>;
>
> up_de_t parse_deck_entry( string const &parse )
> {
> size_t delimiter = parse.find( ": " );
> if( delimiter == string::npos || !delimiter || delimiter ==
> parse.size() - 2 )
> return up_de_t();
> return make_unique<deck_entry>( string( parse.begin(),
> parse.begin() + delimiter ),
> string( parse.begin() + (delimiter
> + 2), parse.end() ) );
> }
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <563-365-8930@kylheku.com> |
|---|---|
| Date | 2021-08-29 18:14 +0000 |
| Message-ID | <20210829110308.870@kylheku.com> |
| In reply to | #162473 |
On 2021-08-29, Bithov Vinu Student <vinub@calday.co.uk> wrote:
> Modifying parse_deck_entry to be the following:
>
> ```
> deck_entry* parse_deck_entry(char* to_parse) {
> char* string_to_parse = strdup(to_parse);
Here you allocate one object, a duplicate of the input string.
> char* a = strsep(&string_to_parse, ": ");
> char* b = strsep(&string_to_parse, "\n");
Here you get two pointers into that string; but there is still
only one object.
You cannot use these pointers to free the string; you need
the original pointer that came from strdup.
I *suspect* that the first call to strsep returns the argument
string, so that a == string_to_parse.
If that is true (and if so, you can assert that condition in the
program), then you can make the assumption that the entry_key
and entry_value of every deck_entry are carved from the same underlying
allocated object, and that it's only necessary to free(entry_key) to
free all the storage.
This kind of thing tends to create problems when the program
is later maintained. Like "I'd like to do create such and such
a feature, but it turns out that I can't do it easily because years
ago some some dolt packed these objects into the same allocation,
and so that all needs refactoring".
If it happens that a != string_to_parse, what you can still do is
have a third pointer in every deck_node: void *storage.
This is a copy of string_to_parse, which is passed to free()
when the node is destroyed.
A more generic way to handle that would be this:
struct deck_node {
char *entry_key;
char *entry_value;
void *destructor_context;
void (*destructor_fn)(struct deck_node *):
};
When a deck node is freed, you don't call free directly, but
rather this:
node->destructor_fn(node);
when a node is created you give it an appropriate destructor_fn based on
how it was created. FOr instance, suppose you create a node whose key
and value are string literals. Then there is nothing to free!
void deck_node_dtor_null(struct deck_node *node)
{
/* nothing to do */
}
struct deck_node *deck_node_from_lits(const char *a, const char *b)
{
deck_node *node = ... allocate it ..
node->entry_key = a;
node->entry_key = b;
node->destructor_context = NULL;
node->destructor_fn = deck_node_dtor_null;
}
Used like this:
deck_node *x = deck_node_from_lits("foo", "bar");
For every manner of allocating a node, you can have a correct
destructor, tied into that node. Then there can be an aggregate mixture
of those different kinds of nodes, yet which you can all free.
[toc] | [prev] | [next] | [standalone]
| From | Lew Pitcher <lew.pitcher@digitalfreehold.ca> |
|---|---|
| Date | 2021-08-29 18:18 +0000 |
| Message-ID | <sggj16$1vg$3@dont-email.me> |
| In reply to | #162473 |
On Sun, 29 Aug 2021 08:34:56 -0700, Bithov Vinu Student wrote:
> Hi,
>
> I have the following definition:
>
> ```
> typedef struct {
> char* entry_key;
> char* entry_value;
> } deck_entry;
> ```
>
> And the following function to parse a string into a deck_entry:
>
> ```
> deck_entry* parse_deck_entry(char* to_parse) {
> char* string_to_parse = strdup(to_parse);
> char* a = strsep(&string_to_parse, ": ");
> char* b = strsep(&string_to_parse, "\n");
> return make_deck_entry(a, b);
> }
> ```
>
> With the test code as follows:
>
> ```
> int main() {
> deck_entry* new_deck = parse_deck_entry("Age: 23\n");
> free_deck_entry(new_deck);
> return 0;
> }
> ```
>
> The program works without segfaulting or anything else, in fact, using a diagnostic function I wrote (print_deck_entry) all the information has been parsed properly with the write formatting, etc. However, running through Valgrind shows:
>
> ```
> ==8494== Memcheck, a memory error detector
> ==8494== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
> ==8494== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
> ==8494== Command: ./box
> ==8494==
> ==8494==
> ==8494== HEAP SUMMARY:
> ==8494== in use at exit: 25 bytes in 1 blocks
> ==8494== total heap usage: 4 allocs, 3 frees, 65 bytes allocated
> ==8494==
> ==8494== LEAK SUMMARY:
> ==8494== definitely lost: 25 bytes in 1 blocks
> ==8494== indirectly lost: 0 bytes in 0 blocks
> ==8494== possibly lost: 0 bytes in 0 blocks
> ==8494== still reachable: 0 bytes in 0 blocks
> ==8494== suppressed: 0 bytes in 0 blocks
> ==8494== Rerun with --leak-check=full to see details of leaked memory
> ==8494==
> ==8494== For lists of detected and suppressed errors, rerun with: -s
> ==8494== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
> ```
>
> Modifying parse_deck_entry to be the following:
>
> ```
> deck_entry* parse_deck_entry(char* to_parse) {
> char* string_to_parse = strdup(to_parse);
> char* a = strsep(&string_to_parse, ": ");
> char* b = strsep(&string_to_parse, "\n");
> deck_entry* tmp = make_deck_entry(a, b);
> free(a);
> free(b);
> free(string_to_parse);
> return tmp;
> }
> ```
>
> ...will still compile but prints the following when run:
>
> ```
> free(): invalid pointer
> Aborted (core dumped)
> ```
>
> I can't imagine anything else that could be causing a memory leak, considering parse_deck_entry() is the only function I've written that is being called in the test code. What have I done wrong and what could I do to improve? Stability and memory-safety are pretty huge for what I'm writing, even though I am writing in C (rather than Rust, etc.)
Let's ignore your revised parse_deck_entry() function for now, and concentrate
on the original parse_deck_entry() that leaked memory.
> deck_entry* parse_deck_entry(char* to_parse) {
> char* string_to_parse = strdup(to_parse);
> char* a = strsep(&string_to_parse, ": ");
> char* b = strsep(&string_to_parse, "\n");
> return make_deck_entry(a, b);
> }
Please bear with me while I reformat your function for clarity:
deck_entry *parse_deck_entry(char *to_parse)
{
char *string_to_parse,
*a,
*b;
string_to_parse = strdup(to_parse);
a = strsep(&string_to_parse,": ");
b = strsep(&string_to_parse,"\n");
return make_deck_entry(a,b);
}
Note that you (implicitly) malloc() memory with the strdup()
call that assigns to string_to_parse. Thus, string_to_parse
contains a pointer that you should, at some point, pass unaltered
to free(), to release the allocated memory.
Now, strsep()
"finds the first token in the [input] string that is delimited
by one of the bytes in the [delimiter] string. This token is
terminated by overwriting the delimiter with a null byte ('\0'),
and [the input string pointer] is updated to point past the token."
This means that each call to strsep() not only updates the /contents/
of the array pointed to by string_to_parse, it also updates the
string_to_parse pointer itself.
So, by using strsep(), you've lost the pointer value that you must give
free() to return the malloc()'ed memory (from strdup()) to the memory
pool.
As string_to_parse is an object local to the parse_deck_entry() function,
and not passed to other functions, it is clear that it is /not/ passed
to free() at any time, and thus, you leak memory.
The fix would be to, within parse_deck_entry(), free() the /original/
value of string_to_parse, after you've used the substrings you coaxed
out with strsep(). But, of course, you've destroyed the original value
of string_to_parse, /and/ (even if you hadn't destroyed it) you would
need to free() that value /after/ the call to make_deck_entry() (in
order to not deallocate the memory pointed to by a and b) but /before/
the return from parse_deck_entry().
So what do you do? You restructure your parse_deck_entry() such that
a) you cache the pointer from strdup() in a variable that you do not
alter,
b) you cache the pointer from make_deck_entry()
c) you free() the cached strdup() result pointer, after the call to
make_deck_entry(), and
d) you return the cached make_deck_entry() pointer
Something like:
deck_entry *parse_deck_entry(char *to_parse)
{
char *temp, /* cache for unaltered strdup() return value */
*string_to_parse, /* strdup() return value, will be altered */
*a,
*b;
deck_entry *result; /* cache for make_deck_entry() return value */
temp = string_to_parse = strdup(to_parse);
a = strsep(&string_to_parse,": "); /* alters string_to_parse */
b = strsep(&string_to_parse,"\n"); /* alters string_to_parse */
result = make_deck_entry(a,b); /* uses storage allocated by strdup() */
free(temp); /* uses unaltered strdup() pointer */
return result;
}
HTH
Addendum: Please notice how I (re)formatted the various object declarations.
With your (apparently) preferred style
char* string_to_parse
you can misread multiple declarations. For instance,
char* string_to_parse, a b;
/does not/ declare
a
to be a pointer to char, even though a naive reading of the
declaration specifiers would lead you to believe so.
However,
char *string_to_parse, a;
has less chance to be misread in that manner.
HTH
--
Lew Pitcher
"In Skills, We Trust"
[toc] | [prev] | [next] | [standalone]
| From | Barry Schwarz <schwarzb@delq.com> |
|---|---|
| Date | 2021-08-29 11:44 -0700 |
| Message-ID | <cvinigd0u1jrb02ch20cequm2nh08copvh@4ax.com> |
| In reply to | #162473 |
On Sun, 29 Aug 2021 08:34:56 -0700 (PDT), Bithov Vinu Student
<vinub@calday.co.uk> wrote:
>Hi,
>
>I have the following definition:
>
>```
>typedef struct {
> char* entry_key;
> char* entry_value;
>} deck_entry;
<snip obsolete code<
>With the test code as follows:
>
>```
>int main() {
> deck_entry* new_deck = parse_deck_entry("Age: 23\n");
> free_deck_entry(new_deck);
See last comment
> return 0;
>}
>```
<snip obsolete errors>
>Modifying parse_deck_entry to be the following:
>
>```
>deck_entry* parse_deck_entry(char* to_parse) {
> char* string_to_parse = strdup(to_parse);
strdup is non-standard but common extension. Most implementations use
malloc to allocate memory, copy the data pointed to by to_parse into
this allocated memory, and return the address of the allocated memory.
Does yours do this also?
> char* a = strsep(&string_to_parse, ": ");
strsep appears to be a function you wrote. Was the standard strtok
function not adequate for your needs? The fact that you pass it the
address of string_to_parse implies that it changes the value stored in
that pointer. If so, then string_to_parse no longer holds the value
returned by malloc (in strdup) and therefore is not a suitable value
to pass to free.
> char* b = strsep(&string_to_parse, "\n");
> deck_entry* tmp = make_deck_entry(a, b);
make_deck_entry appears to be another function you wrote. After it
allocates space for a new deck_entry, does it assign the values held
by a and b to the structure members or does it copy the data a and b
point to newly allocated memory pointed to by the structure members?
> free(a);
It is possible that a holds the original value of string_to_parse so
this is would be legal. *****BUT***** it is premature; see the
comment on the return statement.
> free(b);
b will definitely not hold the original value so this is not legal.
> free(string_to_parse);
Ditto
> return tmp;
The only reason for returning tmp is so the calling program can do
something with the structure. If make_deck_entry assigned its
parameters to the members of the new structure, the value of both
members of the structure would now be indeterminate. The value of a
pointer that pointed to allocated memory becomes indeterminate when
than memory is freed (the free(a) statement also frees the memory
pointed to by b). Any attempt to dereference such a pointer produces
undefined behavior. While the structure itself is accessible, the
data its members pointed to is not.
>}
>```
>
>...will still compile but prints the following when run:
>
>```
>free(): invalid pointer
>Aborted (core dumped)
>```
>
>I can't imagine anything else that could be causing a memory leak,
>considering parse_deck_entry() is the only function I've written
Who wrote make_deck_entry?
>that is being called in the test code. What have I done wrong and
>what could I do to improve? Stability and memory-safety are pretty
>huge for what I'm writing, even though I am writing in C (rather than Rust, etc.)
You have two complementary requirements:
Keep the allocated memory as long as it is needed.
Free the allocated memory when it is no longer needed.
As others have said, every allocation (including implied ones such as
strdup) requires a corresponding free. If the function doing the
allocation cannot free the memory (because it will be used by the
calling function), then it becomes the calling function's
responsibility to keep track and eventually call free.
If make_deck_entry copied strings instead of assigning the pointer
values, then the two structure members would also point to allocated
memory. Freeing the structure (in main) before freeing the memory
pointed to by the members would also cause a memory leak.
--
Remove del for email
[toc] | [prev] | [next] | [standalone]
| From | Lew Pitcher <lew.pitcher@digitalfreehold.ca> |
|---|---|
| Date | 2021-08-29 19:04 +0000 |
| Message-ID | <sgglni$1vg$5@dont-email.me> |
| In reply to | #162482 |
FWIW On Sun, 29 Aug 2021 11:44:40 -0700, Barry Schwarz wrote: > strdup is non-standard but common extension. strdup() is defined in the Open Group (POSIX) Base Specifications Issue 6, circa 2004. The Open Group's Base Specifications define the minimum standards for the Unix operating system, including standardized extensions to the C library. [snip] > strsep appears to be a function you wrote. strsep() comes from the 4.4 BSD Unix standard C library extensions. [snip] -- Lew Pitcher "In Skills, We Trust"
[toc] | [prev] | [next] | [standalone]
| From | Barry Schwarz <schwarzb@delq.com> |
|---|---|
| Date | 2021-08-29 14:15 -0700 |
| Message-ID | <j4unighpu26r311bai13k1hgjdk286mb15@4ax.com> |
| In reply to | #162483 |
On Sun, 29 Aug 2021 19:04:18 -0000 (UTC), Lew Pitcher <lew.pitcher@digitalfreehold.ca> wrote: >FWIW > >On Sun, 29 Aug 2021 11:44:40 -0700, Barry Schwarz wrote: > >> strdup is non-standard but common extension. > >strdup() is defined in the Open Group (POSIX) Base Specifications Issue 6, >circa 2004. The Open Group's Base Specifications define the minimum standards >for the Unix operating system, including standardized extensions to the C >library. > >[snip] >> strsep appears to be a function you wrote. > >strsep() comes from the 4.4 BSD Unix standard C library extensions. > >[snip] And if this were comp.unix.programmer then what you say would be relevant but the functions are not standard in C. -- Remove del for email
[toc] | [prev] | [next] | [standalone]
| From | scott@slp53.sl.home (Scott Lurndal) |
|---|---|
| Date | 2021-08-29 21:19 +0000 |
| Message-ID | <wRSWI.5174$lC6.1116@fx41.iad> |
| In reply to | #162484 |
Barry Schwarz <schwarzb@delq.com> writes: >On Sun, 29 Aug 2021 19:04:18 -0000 (UTC), Lew Pitcher ><lew.pitcher@digitalfreehold.ca> wrote: > >>FWIW >> >>On Sun, 29 Aug 2021 11:44:40 -0700, Barry Schwarz wrote: >> >>> strdup is non-standard but common extension. >> >>strdup() is defined in the Open Group (POSIX) Base Specifications Issue 6, >>circa 2004. The Open Group's Base Specifications define the minimum standards >>for the Unix operating system, including standardized extensions to the C >>library. >> >>[snip] >>> strsep appears to be a function you wrote. >> >>strsep() comes from the 4.4 BSD Unix standard C library extensions. >> >>[snip] > >And if this were comp.unix.programmer then what you say would be >relevant but the functions are not standard in C. And if this were comp.lang.std.c your point would be relevent.
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | comp.lang.c
csiph-web