I want to remove the i-th member of a string array, and bring every member which comes after it one place prior (the i+1-th member to i and so on). I came up with the following code:
for (int j = i; j < arrSize - 1; j++) {
strcpy(members[j],members[j+1]);
}
free(members[arrSize-1]);
But that got me thinking that it might be wrong. For example, if the i-th place member contains the name "John", while the (i+1)-th place members contains the name "Joshua", which means each string is in a different length, would there be any memory leaks or any problem? Thanks in advance!
EDIT: The definiton of members:
members = malloc(maxMembersNum * sizeof(char*));
Rather than copy the contents of the strings, why not move the pointers around? That is:
for (int j = i; j < arrSize - 1; j++) {
char *temp = members[j];
members[j] = members[j+1];
members[j+1] = temp;
}
free(members[arrSize-1]);
As the comments said, the definition of members determines the outcome of the function.
If it is:
char* members[];
then it is an array of pointers, using strcpy will overwrite memory and you will eventually crash unless all of those buffers are allocated and the same size. In this case, you can just copy the pointers with
members[j] = members[j+1]
if it is:
std::string members[];
then you can treat it as a normal array and dispense with strcpy and free (just use =).
if it is:
char members[80][80]; // fixed size pre-allocated buffer
then your code will work, but free will not.
It would be simpler if lines and arrSize were members of a structure that you could pass in as a unit, but absent that:
void remove_by_index(char **lines, int line, int *arrSize) {
if (line >= *arrSize) return;
*arrSize -= 1;
if (lines[line]) free(lines[line]);
memmove(lines + line, lines + line + 1, ((*arrSize - line) * sizeof(char *)));
lines[*arrSize] = NULL;
}
Strictly speaking, either arrSize has to change to reflect deletion, or else the deleted cell has to be marked with NULL, but it's not necessary to do both as I have done here (though it's not a bad idea).
Also note that this will fail if two members of the array point to the same string, as will the other answers here--for that you'll need a more complex data structure.
Related
Recently I was pondering over this question: how to make an easier way to iterate over an array of pointer in C.
If I create an array of string in C, it should look like this right?
int size = 5;
char ** strArr = (char **) malloc(sizeof(char *) * size);
if (strArr == NULL) return;
But the problem is, when you want to iterate over this array for some reason (like printing all values inside it), you have to keep track of its current size, storing in another variable.
That's not a problem, but if you create lots of arrays, you have to keep track of every single one of their sizes inside the code. If you pass this array to another function, you must pass its size as well.
void PrintValues (char ** arr, int size) {
for (int i = 0; i < size; i++)
printf("%s\n", arr[i]);
}
But when iterating over a string, it's different. You have the '\0' character, which specifies the end of the string. So, you could iterate over a string like this, with not need to keep its size value:
char * str = (char *) malloc(sizeof(char) * 4);
str[0] = 'a';
str[1] = 'b';
str[2] = 'c';
str[3] = '\0';
for (int i = 0; str[i] != '\0'; i++)
printf("%c", str[i]);
printf("\n");
Now my question:
Is it ok or morally right to allocate +1 unit in an array of pointers to maintain its tail as NULL?
char ** strArr = (char **) malloc(sizeof(char *) * (5 +1);
if (strArr == NULL) return;
strArr[0] = PseudoFunc_NewString("Car");
strArr[1] = PseudoFunc_NewString("Car#1");
strArr[2] = PseudoFunc_NewString("Car#2");
strArr[3] = PseudoFunc_NewString("Tree");
strArr[4] = PseudoFunc_NewString("Tree#1");
strArr[5] = NULL; // Stop iteration here as next element is not allocated
Then I could use the NULL pointer to control the iterator:
void PrintValues (char ** arr) {
for (int i = 0; arr[i] != NULL; i++)
printf("%s\n", arr[i]);
}
This would help me to keep the code cleaner, though it would consume more memory as a pointer size is larger than a integer size.
Also, when programming with event-based libraries, like Gtk, the size values would be released from the stack at some point, so I would have to create a pointer to dynamically store the size value for example.
In cases like this, it ok to do this? Or is it considered something bad?
Is this technique only used with char pointers because char type has a size of only 1 byte?
I miss having a foreach iterator in C...
Now my question: Is it ok or morally right to allocate +1 unit in an array of pointers to maintain its tail as NULL?
This is ok, the final NULL is called a sentinel value and using one is somewhat common practice. This is most often used when you don't even know the size of the data for some reason.
It is however, not the best solution, because you have to iterate over all the data to find the size. Solutions that store the size separately are much faster. An arrays of structs for example, containing both size and data in the same place.
Now my question: Is it ok or morally right to allocate +1 unit in an array of pointers to maintain its tail as NULL?
In C this is quite a common pattern, and it has a name. You're simply using a sentinel value.
As long as your list can not contain null pointers normally this is fine. It is a bit error-prone in general however, then again, that's C for you.
It's ok, and is a commonly used pattern.
As an alternative you can use a struct, in there you can create a size variable where you can store the current size of the array, and pass the struct as argument. The advantage is that you don't need to iterate through the entire array to know its size.
Example:
Live demo
#include <stdlib.h>
#include <stdio.h>
typedef struct
{
char **strArr;
int size;
} MyStruct;
void PrintValues(MyStruct arr) //pass the struct as an argument
{
for (int i = 0; i < arr.size; i++) //use the size passed in the struct
printf("%s\n", arr.strArr[i]);
}
int main()
{
// using the variable to extract the size, to avoid silent errors
// also removed the cast for the same reason
char **strArr = malloc(sizeof *strArr * 5);
if (strArr == NULL) return EXIT_FAILURE;
strArr[0] = "Car";
strArr[1] = "Car#1";
strArr[2] = "Car#2";
strArr[3] = "Tree";
strArr[4] = "Tree#1";
MyStruct strt = { strArr, 5 }; // initialize the struct
PrintValues(strt); //voila
free(strArr); // don't forget to free the allacated memory
return EXIT_SUCCESS;
}
This allows for direct access to an index with error checking:
// here if the array index exists, it will be printed
// otherwise no, allows for O(1) access error free
if(arr.size > 6){
printf("%s\n", arr.strArr[6]);
}
I am trying to shift the elements in a dynamically created 3d array by one index, so that each element [i][j][k] should be on [i+1][j][k].
This is how my array creation looks like
typedef struct stencil{
int ***arr;
int l;
int m;
int n;}matrix;
void createMatrix(matrix *vector){
vector->arr = (int***) malloc(sizeof(int**) * (vector->l+2));
for (int i = 0; i< vector->l+2; ++i) {
vector->arr[i] = (int**) malloc(sizeof(int*) * (vector->m+2));
for (int j = 0; j < vector->m+2; ++j) {
vector->arr[i][j] = (int*) calloc((vector->n+2),sizeof(int));
}
}
}
This is basically what I want to achieve with memmove
for(int i = vector->l-1; i >= 0; --i){
for(int j = vector->m; j >= 0; --j){
for(int k = vector->n; k >= 0; --k){
vector->arr[i+1][j][k] = vector->arr[i][j][k];
}
}
}
for some reason memmove shifts 2 indices.
memmove(&(vector->arr[1][1][1]), &(vector->arr[0][1][1]), (vector->l+2)*(vector->m+2)*(vector->n)*sizeof(int*));
Could anyone give me a hint?
When you create a dynamic multi-dimensional array like this, the array contents are not contiguous -- each row is a separate allocation. So you can't move it all with a single memmov().
But you don't need to copy all the data, just shift the pointers in the top-level array.
int **temp = arr[l-1]; // save last pointer, which will be overwritten
memmov(&arr[1], &arr[0], sizeof(*arr[1]));
arr[0] = temp;
I've shifted the last element around to the first, to avoid having two elements that point to the same data. You could also free the old last element (including freeing the arrays it points to) and create a new first element, but this was simpler.
Compile with a higher optimization level (-O3). Obtain a direct reference on vector->arr instead of forcing dereferencing on every single array access.
Your call to memmove looks half correct under the assumption that you allocated arr as continuous memory. However, since you said "dynamic", I very much doubt that. Plus the size calculation appears very much wrong, with the sizeof(int*).
I suppose arr is not int arr[constexpr][constexpr][constexpr] (single, continuous allocation), but rather int ***arr.
In which case the memmove goes horribly wrong. After moving the int** contents of the arr field by one (which actually already did the move), it caused a nasty overflow on the heap, most likely by chance hitting also a majority of the int* allocations following.
Looks like a double move, and leaves behind a completely destroyed heap.
Simply doing this would work (Illustrating in a 3d array)
memmove(arr[1], arr[0], Y*Z*sizeof(int));
where Y and Z denotes the other 2 dimensions of the 2d array.
Here arr[X][Y][Z] is the int array where X>=2.
In case of dynamically allocated memory you need to do each continuous chunk one by one. Then it would work.
In C how do I assign location [i-1] in a char array of pointers to location i in that same array?
For instance, say I have declared char *word[m->words_in_msg+1];
If I wanted to assign the location of i-1 to i how would I do that? I currently have a for loop as such:
for (int i = 2; i < m->words_in_msg; i++){
&word[i - 1] = &word[i];
}
However, this is giving me the compile error "lvalue required as left operand of assignment". I think this is because it is reading the left hand side &word[i - 1] as a pointer location instead of a value but I'm not sure how I would tell it that the value stored in that location is what I want to reassign.
Any help is appreciated, thanks! The C pointer mechanics are not strong with this one. : P
First of all it is not clear whether these pointers were dynamically allocated. If they were dynamically allocated and the array is the owner of the pointers then the code will look like
free( word[1] );
for (int i = 2; i < m->words_in_msg; i++)
{
word[i - 1] = word[i];
}
If the pointers were not dynamically allocated or the array is not the owner of the pointers then you may write simply
for (int i = 2; i < m->words_in_msg; i++)
{
word[i - 1] = word[i];
}
Take into account that you could use standard function memmove declared in header <string.h>
You already declared an array of pointers, you just have to pass it adress, word[some_index] already hold it.
word[i - 1] = word[i];
If you want to put each element to the next position, you shouldn't iterate from first to last. Otherwise, you'll overwrite the element in the next position before moving it.
I am supposed to follow the following criteria:
Implement function answer4 (pointer parameter and n):
Prepare an array of student_record using malloc() of n items.
Duplicate the student record from the parameter to the array n
times.
Return the array.
And I came with the code below, but it's obviously not correct. What's the correct way to implement this?
student_record *answer4(student_record* p, unsigned int n)
{
int i;
student_record* q = malloc(sizeof(student_record)*n);
for(i = 0; i < n ; i++){
q[i] = p[i];
}
free(q);
return q;
};
p = malloc(sizeof(student_record)*n);
This is problematic: you're overwriting the p input argument, so you can't reference the data you were handed after that line.
Which means that your inner loop reads initialized data.
This:
return a;
is problematic too - it would return a pointer to a local variable, and that's not good - that pointer becomes invalid as soon as the function returns.
What you need is something like:
student_record* ret = malloc(...);
for (int i=...) {
// copy p[i] to ret[i]
}
return ret;
1) You reassigned p, the array you were suppose to copy, by calling malloc().
2) You can't return the address of a local stack variable (a). Change a to a pointer, malloc it to the size of p, and copy p into. Malloc'd memory is heap memory, and so you can return such an address.
a[] is a local automatic array. Once you return from the function, it is erased from memory, so the calling function can't use the array you returned.
What you probably wanted to do is to malloc a new array (ie, not p), into which you should assign the duplicates and return its values w/o freeing the malloced memory.
Try to use better names, it might help in avoiding the obvious mix-up errors you have in your code.
For instance, start the function with:
student_record * answer4(const student_record *template, size_t n)
{
...
}
It also makes the code clearer. Note that I added const to make it clearer that the first argument is input-only, and made the type of the second one size_t which is good when dealing with "counts" and sizes of things.
The code in this question is evolving quite quickly but at the time of this answer it contains these two lines:
free(q);
return q;
This is guaranteed to be wrong - after the call to free its argument points to invalid memory and anything could happen subsequently upon using the value of q. i.e. you're returning an invalid pointer. Since you're returning q, don't free it yet! It becomes a "caller-owned" variable and it becomes the caller's responsibility to free it.
student_record* answer4(student_record* p, unsigned int n)
{
uint8_t *data, *pos;
size_t size = sizeof(student_record);
data = malloc(size*n);
pos = data;
for(unsigned int i = 0; i < n ; i++, pos=&pos[size])
memcpy(pos,p,size);
return (student_record *)data;
};
You may do like this.
This compiles and, I think, does what you want:
student_record *answer4(const student_record *const p, const unsigned int n)
{
unsigned int i;
student_record *const a = malloc(sizeof(student_record)*n);
for(i = 0; i < n; ++i)
{
a[i] = p[i];
}
return a;
};
Several points:
The existing array is identified as p. You want to copy from it. You probably do not want to free it (to free it is probably the caller's job).
The new array is a. You want to copy to it. The function cannot free it, because the caller will need it. Therefore, the caller must take the responsibility to free it, once the caller has done with it.
The array has n elements, indexed 0 through n-1. The usual way to express the upper bound on the index thus is i < n.
The consts I have added are not required, but well-written code will probably include them.
Altought, there are previous GOOD answers to this question, I couldn't avoid added my own. Since I got pascal programming in Collegue, I am used to do this, in C related programming languages:
void* AnyFunction(int AnyParameter)
{
void* Result = NULL;
DoSomethingWith(Result);
return Result;
}
This, helps me to easy debug, and avoid bugs like the one mention by #ysap, related to pointers.
Something important to remember, is that the question mention to return a SINGLE pointer, this a common caveat, because a pointer, can be used to address a single item, or a consecutive array !!!
This question suggests to use an array as A CONCEPT, with pointers, NOT USING ARRAY SYNTAX.
// returns a single pointer to an array:
student_record* answer4(student_record* student, unsigned int n)
{
// empty result variable for this function:
student_record* Result = NULL;
// the result will allocate a conceptual array, even if it is a single pointer:
student_record* Result = malloc(sizeof(student_record)*n);
// a copy of the destination result, will move for each item
student_record* dest = Result;
int i;
for(i = 0; i < n ; i++){
// copy contents, not address:
*dest = *student;
// move to next item of "Result"
dest++;
}
// the data referenced by "Result", was changed using "dest"
return Result;
} // student_record* answer4(...)
Check that, there is not subscript operator here, because of addressing with pointers.
Please, don't start a pascal v.s. c flame war, this is just a suggestion.
Yesterday I asked a similar question regarding how to free allocated memory for a sub-string. Now I have one more question regarding the same problem (involving a set of conditions), how could I free the following sub-string without doing double free?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct st_ex {
char product[16];
float price;
};
struct st_temp {
char *prod;
};
char *temp = NULL;
// from stackoverflow
char* substr( const char* source, size_t start, size_t end )
{
char* dest = malloc( end - start + 1) ;
memcpy( dest, &source[start], end - start ) ;
dest[end - start] = 0 ;
return dest ;
}
int main()
{
struct st_ex structs[] = {{"mp3 player", 2.0f}, {"plasma tv", 20.0f},
{"notebook", 10.0f}, {"smartphone", 49.9f},
{"dvd player", 10.0f}, {"matches", 0.2f }};
struct st_temp **temp_struct;
size_t j, i;
temp_struct = malloc(sizeof *temp_struct * 6);
for (j = 0; j < 6; j++)
temp_struct[j] = malloc(sizeof *temp_struct[j]);
size_t structs_len = sizeof(structs) / sizeof(struct st_ex);
// NOTE: that structs_len may vary in size - not just 6
for(i=0; i<structs_len; i++){
if (i == 0)
temp_struct[i]->prod = "+";
else if(i == 1)
temp_struct[i]->prod = "Bar";
else if(i == 5)
temp_struct[i]->prod = "Foo";
else {
temp = substr(structs[i].product, 0, 4);
temp_struct[i]->prod = temp;
}
}
for(i=0; i<6; i++ )
printf("%s\n",temp_struct[i]->prod);
for(i = 0; i < 6; i++ ){
/* can I do something like this? */
/*if (i != 0 || i != 1 || i != 5)*/
free(temp_struct[i]->prod);
free(temp_struct[i]);
}
free(temp_struct);
return 0;
}
The problem is that sometimes you set temp_struct[i]->prod to a quoted string ("Bar") which you cannot free and sometimes to the result of a substr call, which you must free.
The easiest solution is to always set it to a string that you must free.
temp_struct[i]->prod = new_string("Bar");
where
char* new_string( const char* source )
{
char* dest = malloc( strlen(source) + 1 ) ;
strcpy(dest, source);
return dest ;
}
or, you have to keep track if you need to free or not
struct st_temp {
char *prod;
int prod_must_be_freed;
};
set prod_must_be_freed to 0 or 1 and check that before you free.
And, finally, the whole thing would be improved by using functions to manipulate these structs rather than just fiddling with them directly. Then you could make a free_st_temp(st_temp*) that checked if prod should be freed, and then freed the struct. Your loop would be
for(i = 0; i < 6; i++ ){
free_st_temp(temp_struct[i]);
}
Substrings do not take up extra memory. They are pointers to parts of already existing strings.
Yes, given that your substr is allocating the memory for the substring with malloc, it's reasonable (necessary, really) to free that memory when you're done with it. That said, I think the way you're doing things right now is extremely fragile and error-prone (to put it mildly). If you have any choice at all, I'd allocate the strings for all the prod members the same way -- if you can't allocate them all statically, then allocate them all dynamically, so when you're freeing structures, you can do so uniformly. Trying to assure that you keep the subscripts matched up to free prod if and only if it was allocated dynamically is practically begging for trouble.
You have an additional problem. When you do temp_struct[i]->prod = "Bar"; You are assigning a const char* to prod. That pointer cannot be freed (the most likely outcome is a crash). So if you want to have your code set up this way such that prod can point to either dynamic memory that you got from malloc or to a constant string literal, you need to also keep track of which one it is and only free the dynamic memory.
The condition in your comment would technically work, but would be very poor form. The best idea is to not mix and match string types in the same pointer. But if you insist on doing it that way, then an improvement would be to add another variable to your struct that is set true when prod needs to be freed and false when it does not.
Yes, although you will want to uncomment that if, and change the conditions in the if to be joined with && rather than || (otherwise it will always be true -- every number is either not equal to zero or not equal to one!)
The substrings stored in temp_struct[i]->prod for i other than 0, 1, and 5, were allocated inside the substr function with malloc, so you can and should deallocate them with free.
Similarly, each temp_struct element was allocated with malloc, and so can and should be deallocated with free.
I'm not sure where you think the double free would be coming from. Are you thinking that when you call free(tmp_struct[i]) the memory pointed to by tmp_struct[i]->prod will also be freed? That isn't the case. When you free a pointer to a structure that contains pointers, the memory for the structure's pointers themselves is deallocated (being that it is part of the structure), but the memory being pointed to by those pointers is not, and must be deallocated seperately (since it is external to the structure). Aside from the mistake in the if condition, the way you have it written is the correct way to do this.