How to 'clear' an array of strings? - c

After the initialisation in main(void):
char *params[MAXPARAMS] = {NULL};
params is passed to different functions.
How can I 'reset' the array just as it was during initialisation (after some other functions stored strings in it)?
Edit: params is used as a parameter list, so it might not be fully populated after certain operations. By 'reset' I meant: I want no string values left inside the array, like how you clear a string array in Java, but keeping the same array size.

Considering the memory allocation is done proerly and it is not freed, I think you need to check the memset() function, if you are targeting the values held the array. Please check the man page here.
Otherwise, if you want to be in the same position as the time of initialization, you can free() the allocated memory and again set the variable as NULL.
Please clarify what do you mean by reset. We'll be able to help out in a batter way then.

I think what you want to do is this,
for(i=0;i<MAXPARAMS;i++)
memset(params[i],'\0',strlen(params[i]));
keeping the length of each string intact.

If params has allocated strings, first free the allocations
for (size_t i=0; i<MAXPARAMS; i++) free(params[i]);
To get everything back to NULL
for (size_t i=0; i<MAXPARAMS; i++) params[i] = NULL;
// or
memset(params, 0, sizeof params);
Suggest combining:
for (size_t i=0; i<MAXPARAMS; i++) {
free(params[i]);
params[i] = NULL;
}

Related

How do I fix this issue I'm having with my lowercase function

I'm trying to make a function that goes through a linked list and finds all strings that contain a substring that the user inputs.
The problem is that its case sensitive and I need it to not be.
My idea was to make everything lowercase while going through the list. And wrote something that should work... I think... but doesn't
char *lowerCase(char* strToLower){
char *lowCase;
strcpy(lowCase, strToLower);
for(int i = 0; lowCase[i]; i++){
lowCase[i] = tolower(lowCase[i]);
}
return lowCase;
}
printf("%s", lowerCase("Name"));
Now, what ideally should pop up is "name", but I instead get nothing.
I get Process returned -1073741819 (0xC0000005), which I think is an error related to pointers or memory? I don't really know because build log doesn't tell me anything.
Any help is appreciated <3
The Problem is that you use strcpy wrong. Please refer to the manpage: https://linux.die.net/man/3/strcpy
You need to actually allocate a buffer for the copied string. You right now just copy it to a random memory location (as lowCase is not initialized).
You need to so:
char *lowerCase(char* strToLower){
char *lowCase = (char *)malloc(strlen(strToLower) + 1); // +1 because of terminator
strcpy(lowCase, strToLower);
for(int i = 0; lowCase[i]; i++){
lowCase[i] = tolower(lowCase[i]);
}
return lowCase;
}
and it should work. But beware: As lowCase was allocated, you also need to free it after use, otherwise you have a memory leak.

C dynamically allocate struct array and its components

What is the correct approach to dynamically allocate a struct array and its components in C? I have managed to do something that works,but I am kind of sceptical if it is correct.
I have the following code:
This is my struct array that I need to dynamically allocate:
typedef struct
{
char *wrong;
char *right;
}Dictionary;
This is the function I call when I need to initialise my struct array:
Dictionary *init_Dictionary(int nr_elem)
{
Dictionary *dict;
dict = malloc(nr_elem*sizeof(Dictionary));
for(int i=0; i<nr_elem; i++)
{
char wrong[101],right[101];
scanf("%s%s",wrong,right);
dict[i].wrong = malloc(strlen(wrong)*sizeof(char));
dict[i].right = malloc(strlen(right)*sizeof(char));
strcpy(dict[i].wrong,wrong);
strcpy(dict[i].right,right);
}
return dict;
}
Then in my main function, I have this:
int nr_elem;
scanf("%d",&nr_elem);
Dictionary *dict;
dict = init_Dictionary(nr_elem);
Also,when I finish work with the struct, how do I free the used memory ?
EDIT Thank you all for the quick and indepth answers!
For each allocation you need to allocate one more location to allow for \0 (NULL terminator) at the end of the string.
dict[i].wrong = malloc(strlen(wrong)*sizeof(char) +1 );
dict[i].right = malloc(strlen(right)*sizeof(char) +1);
To free, you first need to free all the pointers right and wrong in the array and then free the main dict array. Optionally, you can NULL the pointers after free.
Dictionary* freeDict(Dictionary *dict, int nr_elem)
{
for (int i=0; i<nr_elem; i++)
{
free(dict->wrong);
free(dict->right);
dict->wrong = NULL;
dict->right = NULL;
}
free (dict);
dict = NULL;
return dict;
}
//To call.
dict = free(dict, nr_elem);
The program design isn't good, you should separate UI from algorithms. Instead of this, you should first take the user input, then store it in 2 strings and pass the strings as parameters to init_Dictionary.
As for the allocation, it is almost correct. But you forgot to allocate space for the null terminator, it should be:
dict[i].wrong = malloc(strlen(wrong)+1);
dict[i].right = malloc(strlen(right)+1);
Multiplying with sizeof(char) isn't meaningful, since the definition of sizeof(char) is always 1 on all systems.
In a production-quality application, you must always check the result of each malloc, then handle errors.
You free memory the same way as you allocated it, but in the opposite order since you need dict itself to be valid until you have deallocated its members:
for(int i=0; i<nr_elem; i++)
{
free(dict[i].wrong);
free(dict[i].right);
}
free(dict);
As a rule of thumb, each call to malloc must be matched with a call to free.
There's a bug in your implementation: strlen(s) does not count the terminating 0-character, so, despite one test may work successfully, this is actually an UB. strdup can do work for you; if you don't have it standard library, simply add 1 when allocating memory for string copies. Or even better: count string length once, then use this value to both allocate enough bytes and copy contents with memcpy.
Otherwise your algorithm is quite useful (provided an array of string pairs is really what you need, with no additional structure like search index or anything).
To deallocate it, add a destructor that performs element-wise deallocation and then frees the whole array:
void destroy(Dictionary *dict, size_t nr_elem) {
for(size_t i = 0; i < nr_elem; ++i) {
free(dict[i].wrong);
free(dict[i].right);
}
free(dict);
}

Free array of pointers

I have this test code :
void test2(){
char** twoDArray = (char**)calloc(3,sizeof(char*));
char* element1 = (char*)calloc(3,sizeof(char));
twoDArray[0] = element1;
twoDArray[1] = element1;
twoDArray[2] = element1;
freeArray(twoDArray,3);
}
void freeArray(char** arr,int size){
if(arr!= NULL){
for(int i =0 ;i < size;i++){
if(arr[i] != NULL){
free(arr[i]);
arr[i] = NULL;
}
}
free(arr);
arr = NULL;
}
}
in second iteration of loop in freeArray arr[1] != NULL give 'true' and error occurs, why ? How to properly free such array ?
Do not cast the return value of calloc()!
You are assigning the very same pointer to each element of the array. I don't know why/how you expect it to work (because then you won't have a 2D-like array, since setting one element of a row will change the element at the same column in all other rows too...)
If you still stick to this design, then you should free the inner "array" only once.
But I suspect you wanted to emulate a sane, working, sensible 2D-array. In this case, you have two options:
I. The hackish solution: almost the same as yours, but you need to callocate memory for each row in a separate step, like this:
twoDArray[0] = calloc(3, sizeof(twoDArray[0]));
twoDArray[1] = calloc(3, sizeof(twoDArray[0]));
twoDArray[2] = calloc(3, sizeof(twoDArray[0]));
(or perhaps use a loop... if you know what they are.)
II. The correct solution: why not allocate a continuous block of memory and avoid all superfluous calls to calloc() and all headache as to what and when needs to be free()d? One array -> one allocation, one deallocation:
char (*arr[3]) = calloc(3, sizeof(arr[0]));
// ...
free(arr);
Nice, simple and more maintainable.
If you are going to make the freeArray function, you have to define some rules about what the array must contain. Your implementation of freeArray makes the assumption that each element of the array is pointing to a separately allocated array of characters, however each element of the array is actually pointing to the same array of characters, so you end up trying to free the same array multiple times, which is not valid.
If freeArray's assumptions are correct, then you'll need to modify how you create the array. If freeArray's assumptions are not correct, you'll need to modify freeArray.

Char* array not retaining value C

For my networking class, we're building a bittorrent client based off the UDP protocol, which is pretty cool but I'm having a ton of trouble with C strings for some reasons.
The first time I receive a packet, I do:
if(server_data == NULL){
server_data = malloc(one_block.total_blocks*sizeof(char*));
int i;
for(i = 0; i < one_block.total_blocks; i++){
server_data[i] = malloc(sizeof(char*));
server_data[i] = "";
}
}
Here, server_data is a char** and one_block is struct that holds packet information and the payload.
Next I do:
server_data[one_block.which_block] = one_block.payload;
blocks_rcv++;
if(blocks_rcv == one_block.total_blocks-1)
done = TRUE; //macro
if(done){
int i;
for(i = 0; i < one_block.total_blocks; i++){
printf("%s", server_data[i];
}
}
All seems well and dandy but for whatever insane reason when I print the contents of server_data before all the packets are received, I see different data from each packet. Afterwards I set done = TRUE and go into that for loop, every spot in the array contains the same string value.
I have no idea why this is happening and I really want to understand how from the beginning of the post to the end, the contents of the array change, even though I verify them through every iteration of the loop that reads in one packet at a time.
This line is the problem:
server_data[i] = "";
It overwrites the allocated pointer, with a pointer to the string literal. And as string literals can't be modified, if you later copy into this pointer, you experience undefined behavior.
If you want to make sure the string is empty, either use calloc, set the first character to '\0', or use strcpy to copy in the new string.
There are a couple of issues going on here:
1) First, server_data, if it's declared as a char**, may or may not be null off the bat, unless you declare it so. I'm not sure if you initialized it to NULL or not. It's a good idea to explicitly initialize it to NULL.
2) I'm not sure from what's going on if you intend for each item of the array server_data to hold a char* (in other words, a reference to a string), or for the array to be a string itself. Is one_block.payload a string, or a set of pointers to strings?
I ran your code with some test values and I'm personally not getting any problems with unexpected values...I think the issue may be in how the struct that holds your payload data is set up. Could you show us your one_block struct? What type of variable/array is one_block.payload?

Copying and freeing malloc'ed pointer

I'm trying to hunt down memory leaks and have found one source. I am malloc'in the pointer in one function and freeing it in another, but I'm missing out on understanding how to copy the value the pointer points to while also being able to free the pointer.
Current implementation (with memory leak):
// This code has been greatly simplified
// and as such does not appear to have any purpose
int foo(){
int bestval = 0;
char *best;
char *match;
for (int i=0;i<3;i++) {
int returnValue = bar(&best);
if (returnValue > 10) {
(1)
match = best;
}
}
printf("%s", match);
(2)
return 0;
}
int bar(char ** best) {
char*s = "Hello!";
*best = malloc(strlen(s) + 1);
strcpy(*best,s);
return 0;
}
Two questions
If I had to free memory at (1) rather than (2), how would I do it so that match would still have what was contained in best?
Should I be doing strcpy to copy best to match? If so, do I have to do another malloc within foo?
A bit of a stab in the dark, assuming there's a loop in Foo...
int foo()
{
int bestval = 0;
char *best;
char *match = 0; // initialize to null
// start some loop
for (int i=0;i<3;i++) {
// fetch the next best value...
int returnValue = bar(&best);
// some check (if best is really best!)
if (returnValue > 10) {
// if match has previously been populated, free it
if(match) {
free(match);
}
// save the new best value
match = best;
}
else {
// not saving best in match, so free it!
free(best);
}
}
// end some loop
// only do this if match was successful?!?
if(match) {
printf("%s", match);
// clean up once the best of the best has been used...
free(match);
}
return 0;
}
In function bar the strcpy should read as
strcpy(*best,s);
In the main function you can copy the value best points to by
strcpy(match, best);
free(best);
match needs to point to a valid memory block before. If you do a
match = best;
free(best);
match will be invalid too because it points at the same freed memory best pointed.
You need to know the size of the string.
At (1) You would be assigning the address of a memory address that has already been freed, you have to do another malloc to match*=malloc(sizestr) and then copy it with memmove or strcpy if you want to free best.
If I understood properly, you want to copy the string into best, then free bests memory and assign ptr to match? if you free best memory before memmoving or strcpying to another location you lose its contents, and if you want to copy it to another location first you need to allocate the memory where you want to copy it to, so you need 2 mallocs on that code.
If I had to free memory at (1) rather than (2), how would I do it so that match would still have what was contained in best?
If you free at position (1), it is not possible to do it so that match would still have what was contained in best.
Should I be doing strcpy to copy best to match? If so, do I have to do another malloc within foo?
match = best;
With the above statement, both are pointing to the same location. So, there is no need to strcpy at all. To do that, allocate memory for match to point to whose length is best+1 and then do a strcpy.
Copying the value of a pointer does not copy the underlying memory. So either, don't free(best) until you are done with match, or you will need to malloc a new buffer, and e.g. memcpy() the contents from one buffer to the other.
Yes, you can malloc and strcpy:
match = malloc(strlen(best) + 1);
strcpy(match, best);
But, if your implementation provides it you can use the strdup() function which is much easier:
match = strdup(best);
If you don't already have strdup(), it's a good idea to create one yourself.
Your current assignment simply assigns the pointers to the same buffer. If you then free() this buffer, you've removed what is contained here (and thus dereferencing it is a bad idea).
You don't need to use strcpy() to copy best to match - you'll be better off freeing it after the printf() (or the last point that it is needed). There's no point over-complicating things with an extra function call or six, just remember to free() memory that you've allocated at the end of each function!

Resources