Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
Say I have a program that allocates a chunk of memory
char* get_date() {
char* date = malloc(100);
return date;
}
And I want to call the function a considerable number of times in the main function.
int main() {
int i;
for (i = 0; i < 10000; i++) {
char *c = get_date();
//do something
free(c);
}
return 1;
}
How can I reduce the number of times a new chunk of memory is allocated and just allocate one and overwrite it afterwards?
Somebody told me about something like this:
char *date = malloc(100);
for (i = 0; i < 10000; i++) {
char *c = get_date(date):
//do something
}
free(date);
But I am not sure how the new function, get_date should look like and why it should work.
Instead of having get_date return a pointer to the buffer with the data produced by the function, make it take a pointer to a buffer into which the data will be written. I.e. the prototype of get_date could be something like
void get_date(char *buf);
However, it might be useful for get_date() to be able to tell not only the starting address of the buffer but also the size of the buffer . That way,
the function can tell if the given buffer is too small (and then return e.g. an int indicating an error code). Hence, the prototype
int get_date(char *buf, size_t len);
might be more useful in practice.
On the caller side, you could then use e.g.
char date[100];
for (i = 0; i < 10000; i++) {
// return value 0 means success
if (get_date(date, sizeof date) == 0) {
//do something
}
}
I.e. in this case, you wouldn't need malloc or free at all.
You are trying to save 10,000 malloc / free calls?
Before you change your code, measure how long it takes. If you are too lazy to measure it, then the speed is not important, so don't change it.
100 bytes? Why are you using malloc() at all?
for (i = 0; i < 10000; i++) {
char c[100]:
//do something
}
If you have a function that returns temporary fixed size memory, the memory can be static:
thread_local char get_date_buffer [100];
char* get_date() {
// change get_date_buffer...
return get_date_buffer;
};
You must not free the return value and you must copy the data when reusing it and recalling the function. Many api-functions use this technique, like glGetString.
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
What is best practice when dealing with functions which return malloc'd pointers to C-strings?
Here's an example:
FILE *f;
char *tmp;
for (i = 0; i <= 10; i++) {
tmp = concat(fn, i);
f = fopen(tmp, "w");
free(tmp);
// read f, do something useful ...
fclose(f);
}
char* concat(char *a, int b) returns a pointer to a new C-string which contains the concatenation of a and b.
Not only do I have to specify a temporary pointer which is then passed to fopen, I also have to free(tmp) every time. I would rather prefer something like this:
FILE *f;
char *tmp;
for (i = 0; i <= 10; i++) {
f = fopen(concat(fn, i), "w");
// read f, do something useful ...
fclose(f);
}
But this of course leads to memory leaks. So what is best practice here? Something like concat(char *a, int b, char *result) where result is expected to be a pre-allocated memory for the resulting C-string? This solution has its disadvantages like limited or not optimal size of result.
A more solid design:
FILE *open_file_number(const char *str, int number)
{
size_t size = strlen(str) + 32;
char *path = malloc(size);
if (path == NULL)
{
return NULL;
}
snprintf(path, size, "%s%d", str, number);
FILE *file = fopen(path, "w");
free(path);
return file;
}
for (i = 0; i <= 10; i++)
{
FILE *file = open_file_number(some_path, i);
if (file != NULL)
{
// Do your stuff
fclose(file);
}
}
Both approaches are used in the industry. In your example, people could make an assumption about the maximum size for the resulting filename and use a local array this way:
for (int i = 0; i <= 10; i++) {
char filename[1024];
snprintf(filename, sizeof filename, "%s%d", fn. i);
FILE *f = fopen(filename, "w");
if (f != NULL) {
// read f, do something useful ...
fclose(f);
} else {
// report the error?
}
}
Note that the truncation can be detected with if (snprintf(filename, sizeof filename, "%s%d", fn. i) >= (int)sizeof filename).
If no assumption should be made about the filename length or if the filename composition method is more complicated, returning an allocated string may be a more appropriate option, but testing for memory allocation errors should also be done:
for (int i = 0; i <= 10; i++) {
char *filename = concat(fn, i);
if (filename == NULL) {
/* handle the error */
...
// break / continue / return -1 / exit(1) ...
}
FILE *f = fopen(filename, "w");
if (f == NULL) {
/* report this error, using `filename` for an informative message */
} else {
// read f, do something useful...
// keep `filename` available for other reporting
fclose(f);
}
free(filename);
}
If you are not ready to perform all this bookkeeping, you should probably use a different language with more elaborate object life cycle management or with a garbage collector.
Finally, using C99 compound literals, you could define concat to fit your simplified use case:
char *concat(char *dest, const char *s, int b) {
sprintf(dest, "%s%d", s, b);
return dest;
}
#define CONCAT(a, b) concat((char[strlen(a) + 24]){""}, a, b)
CONCAT defines an unnamed local variable length char array of the appropriate size and constructs the concatenation of string a and int b into it. I changed the case to uppercase to underscore the fact that a is evaluated twice in the expansion, and thus should not be an expression that involve side-effects.
You could use this macro as expected in your second code fragment:
FILE *f;
char *tmp;
for (i = 0; i <= 10; i++) {
f = fopen(CONCAT(fn, i), "w");
// read f, do something useful ...
fclose(f);
}
I probably would not recommend this type of usage, but this is only my opinion.
What is best practice when dealing with functions which return malloc'd pointers to C-strings?
Best practice: don't use them. A library expecting the caller to free returned data is almost certainly badly designed, with very few exceptions. We know this from 40 years of C language history, where crappily written libraries have created millions upon millions of memory leak bugs.
The basic rule of sane, useful library API design is:
Whoever allocates something is responsible for cleaning up their own mess.
Since C doesn't have RAII or constructors/destructors, that unfortunately means that the sane library needs to provide you with a function for the clean-up and you need to remember to call it. If it doesn't provide such a function, you might want to consider writing wrapper functions that do this - correcting the bad library design for them.
If you are the one implementing the library, you should always try to leave memory allocation to the caller, whenever possible. This is traditionally done by the function taking a pointer to a buffer which it writes to. Then either leaves it to the caller to allocate enough memory (like strcpy/strcat), or alternatively provide a variable with maximum buffer size, after which the function returns how much of the buffer it actually used (like fgets).
In your example, a soundly designed concat would perhaps look like
const char* concat (char* restrict dst, const char* restrict src, int i);
Where src is the source string, i is the integer to add and dst is a large-enough buffer provided by the caller. Optionally, the function returns a pointer equivalent to dst, for convenience. The above also implements proper const correctness plus a micro-optimization with restrict that means that the pointers passed aren't allowed to overlap.
Usage:
char buf [LARGE_ENOUGH];
fp = fopen(concat(buf, foo, i), "w");
Your first code snippet, where you save the returned pointer and free it when you're done using it, is the proper way to work with a function returning malloc'ed memory.
There are several POSIX functions, such as strdup and getline, that work in this manner, so this is a well known idiom.
Alternatives are:
Return a pointer to a static buffer. This has the disadvantage that it is not thread safe and also can't be called twice in one expression.
Accept a pointer to a properly sized buffer, in which case properly sizing the buffer is up to the caller.
If you know the maximum size of your strings, you could also do something like this:
char* concat_(char* buf, size_t s, char *a, int b)
{
/* ... your code ... */
return buf;
}
#define concat(a, b) concat_((char[100]){""}, 100, (a), (b))
The macro allocates an unnamed local variable and passes it on to the concat_ function. This function can then do whatever it did before, and just return the pointer to that same object. No malloc, no free, no worries (other than possibly blowing up your stack, if you make the buffer too big).
Edit:
Please note that, as Gerhardh pointed out in the comments, this creates a local object (which has automatic storage duration), so the pointer returned by the macro is only valid within the same block where that macro was actually called. Therefore you can't for instance use that pointer as a return value of the functoin which called the macro.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I have a question about how to make a temporary string in C. What I mean is I would like to create a string on every iteration step and free the variable after it is not useful anymore.
I have seen question similar to this one, but they differ in significant ways.
So right now I have something similar to this:
for (int i = 0; i < array_size; i++) {
//aray1 and array2 are arrays of strings
char* temporary_value = make_hash(array1[i], array2[i], size[i]);
if (is_valid(temporary_value)) {
//Code, that doesn't interferate in memory, but uses temporary_value - mostly just compare to it
}
free(temporary_value);
}
Where make_hash mallocs the memory depending on size[i].
But it feels so wrong and sometimes returns segment fault.
My ideas to improve this are:
Make string array and free it after the loop
Put "make_hash" code inside the for-loop and just realloc memory during iteration and free the temporary_value after the for-loop
But these solutions seem to be also bad. How would you approach this kind of problem?
When functions return objects of a known size, it is often better to let the caller handle allocations than the functions themselves, the caller often know what kind of allocation is best (automatic, static, heap, etc..). Just pass the pointer to where you want the result when calling the function.
Hash functions often returns hashes of fixed size, so i would go for this:
for (int i = 0; i < array_size; i++) {
char buffer[HASH_SIZE];
/*
`make_hash` writes result into `buffer` and returns `buffer` on success, or
`NULL` on error
*/
char* temporary_value = make_hash(buffer, array1[i], array2[i], size[i]);
if (is_valid(temporary_value)) {
//Code, that doesn't interferate in memory, but uses temporary_value - mostly just compare to it
}
}
In case your hash function does not return a fixed-size hash value, and you want the possibility to realloc your buffer, then pass a pointer to a pointer to your buffer, together to a pointer to a variable holding the buffer size:
make_hash(char **buffer, size_t *buffer_size, const char *str1, const char *str2, size_t s)
{
size_t new_size = .....;
if (new_size > *buffer_size)
{
char *tmp = realloc(*buffer, new_size);
if (!tmp)
return NULL;
*buffer = tmp;
*buffer_size = new_size;
}
/*
Calculate hash, and store it wherever `b` is pointing
*/
char *b = *buffer;
.......
return b; /* or `NULL` on error */
}
char *buffer = NULL;
size_t buffer_size = 0;
for (int i = 0; i < array_size; i++) {
char* temporary_value = make_hash(&buffer, &buffer_size, array1[i], array2[i], size[i]);
if (is_valid(temporary_value)) {
//Code, that doesn't interferate in memory, but uses temporary_value - mostly just compare to it
}
}
free(buffer);
If you have a cheap way of calculating the hash size, without calling make_hash() you could also go for the first solution together with a variable-length array:
for (int i = 0; i < array_size; i++) {
size_t buffer_size = hash_size(.....);
char buffer[buffer_size];
/*
`make_hash` writes result into `buffer` and returns `buffer` on success, or
`NULL` on error
*/
char* temporary_value = make_hash(buffer, array1[i], array2[i], size[i]);
if (is_valid(temporary_value)) {
//Code, that doesn't interferate in memory, but uses temporary_value - mostly just compare to it
}
}
How I would approach this is not freeing within the loop. malloc/free are usually very expensive system calls which you do not want to do if you know that you will have to call malloc again.
The correct way to do this would be malloc once, and then realloc on subsequent calls using the same block of memory, and then free once you're outside the loop.
The segmentation fault might come from a number of factors, are the arrays the same length, array1, array2 and size. you are also freeing memory without checking if it was allocated.
I will rather have something like this.
if (temporary_value != NULL) {
free(temporary_value);
}
It has been long since coding in C but that should help in troubleshooting.
I'm creating a C-library with .h and .c files for a ring buffer. Ideally, you would initialize this ring buffer library in the main project with something like ringbuff_init(int buff_size); and the size that is sent, will be the size of the buffer. How can I do this when arrays in C needs to be initialized statically?
I have tried some dynamically allocating of arrays already, I did not get it to work. Surely this task is possible somehow?
What I would like to do is something like this:
int buffSize[];
int main(void)
{
ringbuffer_init(100); // initialize buffer size to 100
}
void ringbuffer_init(int buff_size)
{
buffSize[buff_size];
}
This obviously doesn't compile because the array should have been initialized at the declaration. So my question is really, when you make a library for something like a buffer, how can you initialize it in the main program (so that in the .h/.c files of the buffer library) the buffer size is set to the wanted size?
You want to use dynamic memory allocation. A direct translation of your initial attempt would look like this:
size_t buffSize;
int * buffer;
int main(void)
{
ringbuffer_init(100); // initialize buffer size to 100
}
void ringbuffer_init(size_t buff_size)
{
buffSize = buff_size;
buffer = malloc(buff_size * sizeof(int));
}
This solution here is however extremely bad. Let me list the problems here:
There is no check of the result of malloc. It could return NULL if the allocation fails.
Buffer size needs to be stored along with the buffer, otherwise there's no way to know its size from your library code. It isn't exactly clean to keep these global variables around.
Speaking of which, these global variables are absolutely not thread-safe. If several threads call functions of your library, results are inpredictible. You might want to store your buffer and its size in a struct that would be returned from your init function.
Nothing keeps you from calling the init function several times in a row, meaning that the buffer pointer will be overwritten each time, causing memory leaks.
Allocated memory must be eventually freed using the free function.
In conclusion, you need to think very carefully about the API you expose in your library, and the implementation while not extremely complicated, will not be trivial.
Something more correct would look like:
typedef struct {
size_t buffSize;
int * buffer;
} RingBuffer;
int ringbuffer_init(size_t buff_size, RingBuffer * buf)
{
if (buf == NULL)
return 0;
buf.buffSize = buff_size;
buf.buffer = malloc(buff_size * sizeof(int));
return buf.buffer != NULL;
}
void ringbuffer_free(RingBuffer * buf)
{
free(buf.buffer);
}
int main(void)
{
RingBuffer buf;
int ok = ringbuffer_init(100, &buf); // initialize buffer size to 100
// ...
ringbuffer_free(&buf);
}
Even this is not without problems, as there is still a potential memory leak if the init function is called several times for the same buffer, and the client of your library must not forget to call the free function.
Static/global arrays can't have dynamic sizes.
If you must have a global dynamic array, declare a global pointer instead and initialize it with a malloc/calloc/realloc call.
You might want to also store its size in an accompanying integer variable as sizeof applied to a pointer won't give you the size of the block the pointer might be pointing to.
int *buffer;
int buffer_nelems;
char *ringbuffer_init(int buff_size)
{
assert(buff_size > 0);
if ( (buffer = malloc(buff_size*sizeof(*buffer)) ) )
buffer_nelems = buff_size;
return buffer;
}
You should use malloc function for a dynamic memory allocation.
It is used to dynamically allocate a single large block of memory with the specified size. It returns a pointer of type void which can be cast into a pointer of any form.
Example:
// Dynamically allocate memory using malloc()
buffSize= (int*)malloc(n * sizeof(int));
// Initialize the elements of the array
for (i = 0; i < n; ++i) {
buffSize[i] = i + 1;
}
// Print the elements of the array
for (i = 0; i < n; ++i) {
printf("%d, ", buffSize[i]);
}
I know I'm three years late to the party, but I feel I have an acceptable solution without using dynamic allocation.
If you need to do this without dynamic allocation for whatever reason (I have a similar issue in an embedded environment, and would like to avoid it).
You can do the following:
Library:
int * buffSize;
int buffSizeLength;
void ringbuffer_init(int buff_size, int * bufferAddress)
{
buffSize = bufferAddress;
buffSizeLength = buff_size;
}
Main :
#define BUFFER_SIZE 100
int LibraryBuffer[BUFFER_SIZE];
int main(void)
{
ringbuffer_init(BUFFER_SIZE, LibraryBuffer ) // initialize buffer size to 100
}
I have been using this trick for a while now, and it's greatly simplified some parts of working with a library.
One drawback: you can technically mess with the variable in your own code, breaking the library. I don't have a solution to that yet. If anyone has a solution to that I would love to here it. Basically good discipline is required for now.
You can also combine this with #SirDarius 's typedef for ring buffer above. I would in fact recommend it.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
i have a linked list of srtings that i need to sort in alphabetical order
and i am tryping to copy the strings to an array and then sort and print them in alphabetical order
void DisplayAll(k *l,p *p)
{
int i,j;
p *temp;
temp = malloc(l->num*sizeof *temp);
for (i = 0; i < l->num; i++)
{
strcpy_s(temp[i].name, 20, p->name);
p = p->next;
i++;
}
for (i = 0; i < l->num - 1; i++){
for (j = i + 1; j< l->num; j++)
{
if (strcmp(temp[i].name, temp[j].name) > 0)
{
strcpy_s(temp->name,20, temp[i].name);
strcpy_s(temp->name[i],20, temp[j].name);
strcpy_s(temp->name[j],20, temp->name);
}
}
for (i = 0; i < l->num-1; i++){
printf("%s\n", temp[i].name);
}
}
this is the k struct and the p stuct
typedef struct p
{
char name[20];
struct p* next;
}p;
typedef struct k
{
int num;
p *head;
}k;
and i getting an Error evey time i run it
There's a couple of problems with your code:
First off: This doesn't look right at all:
strcpy_s(temp->name,20, temp[i].name);
strcpy_s(temp->name[i],20, temp[j].name);
strcpy_s(temp->name[j],20, temp->name);
according to the docs:
errno_t strcpy_s(
char *strDestination,
size_t numberOfElements,
const char *strSource
);
The first and last arguments are expected to be of the type char*. You've defined struct p .name as char[20], so temp->name[i] will be of type char.
I guess you're actually trying to do something like this:
//get struct p at offset i in temp, access member "name"
strcpy_s(temp[i].name, 20, temp[j].name);
Secondly: You're allocating memory for temp, but you fail to free it once you're done (ie when your function returns). You have, in other words, a memory leak. Sure, once your program exits, the memory is almost certainly going to be freed, but if you're writing programs that have to run for extended periods of time, and functions like this are getting called several times over, your memory consumption will gradually increase, and you don't want that to happen. In short, after your last loop (where you print everything out), add this:
free(temp);
Edit
You've added the free call now, and -correctly- wrap it in an if (temp). However: if malloc had returned a NULL pointer, don't you think you should've cought that at the beginning of the function?
temp = malloc(l->num * sizeof *temp);
if (!temp)
return;//or return int to indicate error or or exit EXIT_FAILURE; or something
There's no reason for you to reach the point where you free(temp) without having successfully allocated the memory.
Third: As #Bluepixy pointed out in his comment, there's a syntax error, too: the if (strcmp(temp[i].name, temp[j].name) > 0) branch is never closed properly: you're missing a closing bracket after the third strcpy_s call.
Lastly, you're allocating enough memory to accomodate l->num structs. You initialize them in such a way that every other struct will be assigned the name member of the next struct p in a list. You're not really making sure that p->next isn't a null pointer. This could cause problems (dereferencing a null pointer). So change the first loop into something like this:
int l_num = l->num;//you'll see why
for (i = 0; i < l_num; i+=2)//increment twice if you want/need to
{
strcpy_s(temp[i].name, 20, p->name);
p = p->next;
if (p == NULL)
{
l_num = i+1;//this is as far as we ought to go in the subsequent loops
break;//or handle error in some way
}
}
After this, replace all your ;i < l->num; conditions in your loops with i < l_num or j < l_num to avoid using uninitialized string values.
Just a final tip: If you're not working on anything too time critical, it might be useful to use calloc instead of malloc, especially when dealing with strings, or use memset(temp[i]->name, 0, 20); to ensure all char[] members are indeed empty strings.
If you find yourself using a lot of str* functions (strncat, strncpy and the like), even something as simple as temp[i]->name[0] = '\0'; can make life a lot easier.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 7 years ago.
Improve this question
So, this is working fine... that means, no compiler errors, it seems that there is no memory leak and it is doing what I wanted it to do. That said should it be working? When I go to books_init I send a local variable to collection, doesn't it mean that when I go back to main it shouldn't be working? (or undefined behavior?). Also, in case you say that I have to malloc it, do I have to free it after? (commented on cleanup)
/* pseudo struct Collection{
size_t size, capacity;
Volume *volumes;
} */
void collection_init(Collection *col, size_t capacity){
col->size = 0;
col->capacity = capacity;
col->volumes = malloc(sizeof(Volume) * capacity);
}
void collection_resize(Collection *col, size_t capacity){
Volume *v = realloc(col->volumes, capacity * sizeof(Volume));
if(!v) return;
col->capacity = capacity;
col->volumes = v;
}
void collection_add(Collection *col, Volume *volume){
if(col->size >= col->capacity)
collection_resize(col, col->capacity * 2);
col->volumes[col->size++] = *volume;
}
void collection_clean(Collection *col){
//for(vol : col->vol) free(vol);
//should I free every element or just volumes?
free(col->volumes);
}
void books_init(Collection *col){
for(int i = 0; i < 25; ++i){
Volume v = {.swag = i};
collection_add(col, &v);
}
}
int main(){
Collection col;
collection_init(&col, 10);
books_init(&col);
for(int i = 0; i < col.size; ++i){
printf("\tVol[%d].id = %d\n", i, col.volumes[i].swag);
}
collection_clean(&col);
return 0;
}
Thanks for your time
This line in books_init
Volume v = {.swag = i};
creates a local variable called v with member swag initialized to i. The address of that variable is then passed to collection_add. That is allowed because v is still in scope.
This line in collection_add
col->volumes[col->size++] = *volume;
makes a copy of the contents of the Volume structure, and stores that copy in the memory that was allocated in collection_init.
After collection_add returns, the variable v in books_init goes out of scope, but that's OK because the contents of v were copied and saved in the memory that col->volumes points to.
When the program ends, collection_clean only needs
free(col->volumes);
to remove all of the Volume copies from memory.
The only flaw I see in your program occurs if realloc fails. In that case, you still write to the Volume array. This will cause a buffer overrun and memory corruption. To avoid this, the collection_add function should verify that the collection_resize function succeeded before performing the copy. For example, you could check again that col->capacity > col->size before doing the copy.
TL;DR your code is fine as long as the realloc always succeeds.