I have an array of pointer to struct, and for any reasons when I print this array, there is a spare element at the end of it, and thus causes the code to print a NULL byte at the end.
Is there anyway I can delete the last chunk of memory?
For example:
typedef struct
{
char *name;
} B;
typedef struct
{
B *var;
} A;
int main() {
int num = 5; //for example
A *foo = malloc(sizeof(A));
B *bar = malloc(num * sizeof(B));
for (int i = 0; i < num; i++) {
bar[i] = *create_b(&bar[i]); // some function that works.
}
foo->var = bar;
while (foo->var != NULL) {
printf("This is %s\n",foo->var->name);
foo->var++;
}
}
Everything is printed out just fine, but there's an unwanted printing at the end of the loop. Something like:
This is A
This is B
This is C
This is D
This is F
This is
Apparently the array only has 5 elements, the last one prints nothing.
Your printing loop is:
foo->var = bar;
while (foo->var != NULL) {
printf("This is %s\n",foo->var->name);
foo->var++;
}
But foo->var will never equal NULL, since you're just incrementing a pointer, so you will eventually read past the end of the bar array and your application will probably crash.
If you replace the while loop with for (int i = 0; i < num; i++), it will print the correct number of elements.
You can't do foo->var++, because there is no place in the array that is set to NULL. Also, using that ++ changes foo->var so after the loop foo->var no longer points at the start of the array, and you can not access the array again.
You need to allocate memory for some end-of-array marker, just like strings has the character \0 to mark the end of the string.
Try the following:
int main() {
int num = 5; //for example
A *foo = malloc(sizeof(A));
B *bar = malloc((num + 1) * sizeof(B)); // +1 for array terminator
for (int i = 0; i < num; i++) {
bar[i] = *create_b(&bar[i]); // some function that works.
}
bar[i].name = NULL; // Use this as a marker to mean end of array
foo->var = bar;
for (B *tmp = foo->var; tmp->name != NULL; tmp++) {
printf("This is %s\n",tmp->name);
}
}
Edit Had some errors in the code.
Your problem is probably in the function create_b, which you did not post.
Edit: no, that's probably wrong, sorry.
But surely this isn't what you want:
bar[i] = *create_b(&bar[i]);
You both pass in the address of bar[i] and set it equal to whatever the return value points to?
Related
I created a struct called PLAYER and I want to create an list that stores the pointers to the PLAYER object.
If I want to accomplish it with
PLAYER **ptr = malloc(10*sizeof(PLAYER *));
How can I assign the pointers to each index? I tried:
PLAYER *a;
PLAYER *b;
ptr[0] = a;
ptr[1] = b;
1.This seems to work. Can I get some explanation on the memory address behind it?
I also tried:
ptr = a;
//increase the address and assign b
ptr += sizeof(PLAYER *);
ptr = b;
2.This does not work correctly I think. Can I see a correct way of assign the list without using the [] brackets?
3.If I allocate only one entry's size and assign multiple ones:
PLAYER **ptr = malloc(1*sizeof(PLAYER *));
ptr[0] = a;
ptr[1] = b;
I can get these PLAYER object by using ptr[0] ptr[1], but will this cause any problems like overwrite other memories?
4.If I use [] brackets, do I need to malloc at each index in order to use it?
PLAYER *ptr[10];
for(int i = 0; i < 10; i++)
ptr[i] = malloc(sizeof(PLAYER *));
5.Do I need to free an array after using it? such as:
char ptr[10] = "abc";
//do something with ptr
free(ptr);
char *ptr2[10] = {"123", "abc"};
free(ptr2);
Any help would be much appreciated!
If you have a PLAYER **ptr = malloc(10*sizeof(PLAYER *));
That means you have to malloc for every ptr[i] = malloc(sizeof(PLAYER));
Accessing the array at indexes would be ptr[i]->somevalue
NOTE: if you have pointers inside the struct you need to allocate for those as well!!
Freeing your memory would be:
for(int i = 0; i<10;i++){
free(ptr[i]->anyAllocatedPointersInside);
free(ptr[i]);
}
free(ptr);
SPECIFICALLY IN THAT ORDER
If you update the post with the full struct I can update mine to more accurately help you.
When in doubt, think of malloc() allocations in these terms: it allocates raw memory, and it doesn't know anything about your structs!
When you think in these terms, you'll get it right.
Let's try to answer to your questions:
You are basically instancing within the stack a pointer, with any content into it, just as int hello;. That integer can contain anything, because you don't set it as in int hello = 2;. The same thing is happening with your pointers: int * hello; will be a pointer (to an integer) that can contain any address. Hence, if you dereference a pointer like that, your chances to get caught into SIGSEGV are not low.
Then, once you have created those pointers that can be anything, you're assigning their address to the pointer of pointers array you've allocated. Don't do that.
That doesn't work correctly, because if you have an array of pointers to a given type, you can simply increment with += n, the compiler will calculate the appropriate "sizeof(type_you're-pointing_to)" and will add that automatically. This is the main purpose of declaring a pointer to a given type.
You're effectively overwriting other memory.
Brackets are just pointer dereferencing: *ptr+n same as ptr[n].
You need to free each line, and then the array of pointers of pointers.
Basically every pointer you get with malloc(), you have to free it with free(). DO NOT call free() to any other pointers that hasn't been spit out from malloc().
Let me show you some code I have just written to show you better:
#include <stdlib.h>
#include <stdio.h>
#include <string.h> // for memset
#define N_POINTERS 4
#define M_PLAYERS_PER_LINE 3
struct PLAYER
{
int id;
int score;
int age;
};
int
main()
{
// Allocate the array of pointers, big enough to old N pointers.
struct PLAYER ** pointers = malloc(N_POINTERS*sizeof(struct PLAYER*));
// Always better zeroize pointers arrays.
memset(pointers, 0, N_POINTERS*sizeof(struct PLAYER *));
// Allocate each line of M `PLAYER` structs.
// Basically we allocate N chunks of memory big enough to contain M PLAYER structs one next each other.
// What we get is something like this:
//
// pointer pointers PLAYER lines
// of pointers array
// [addrP] -> [addr0] -> [PLAYER0 PLAYER1 PLAYER2] .. M
// [addr1] -> [PLAYER0 PLAYER1 PLAYER2] .. M
// ...N
//
int id = 0;
for (int i = 0; i < N_POINTERS; ++i)
{
pointers[i] = malloc(M_PLAYERS_PER_LINE*sizeof(struct PLAYER));
// Set the data you want to the structs.
for (int k = 0; k < M_PLAYERS_PER_LINE; ++k)
{
pointers[i][k].id = id++;
pointers[i][k].score = 123 + k;
pointers[i][k].age = 33 + i;
}
}
// Print data.
// Here we use a single PLAYER pointer that will
// traverse the entire PLAYER matrix.
struct PLAYER * player;
for (int i = 0; i < N_POINTERS; ++i)
{
for (int k = 0; k < M_PLAYERS_PER_LINE; ++k)
{
// Assign the current PLAYER to our pointer.
player = pointers[i] + k;
// Print PLAYER data, by reading the pointed struct.
printf("Player: #%i age:%i score:%d\n", player->id, player->age, player->score);
}
}
// Deallocate!
for (int i = 0; i < N_POINTERS; ++i)
{
// Deallocate each line chunk.
free(pointers[i]);
}
// Deallocate the array of pointers.
free(pointers);
return 0;
}
As a bonus track, if you need to allocate a matrix of M*N PLAYER structs, you should also look at this code, that will allocate M*N PLAYER structs into one unique memory block, one next each other, which is much more easier to manage, as you can see by the code itself:
#include <stdlib.h>
#include <stdio.h>
#define LINES 4
#define COLUMNS 3
#define GET_ARRAY_POS(lin, col) (col+(lin*COLUMNS))
struct PLAYER
{
int id;
int score;
int age;
};
int
main()
{
// Allocate a *FLAT* array of PLAYER structs, big enough to
// contain N*M PLAYER structs, one next each other.
struct PLAYER * array = malloc(LINES*COLUMNS*sizeof(struct PLAYER));
// Set the data you want to the structs.
int id = 0;
for (int lin = 0; lin < LINES; ++lin)
{
for (int col = 0; col < COLUMNS; ++col)
{
int pos = GET_ARRAY_POS(lin, col);
array[pos].id = id++;
array[pos].score = 123 + col;
array[pos].age = 33 + lin;
}
}
// Print data.
// Here we use a single PLAYER pointer that will
// traverse the entire PLAYER matrix.
for (int i = 0; i < (LINES*COLUMNS); ++i)
{
// Print PLAYER data, by reading the pointed struct.
printf("Player: #%i age:%i score:%d\n", array[i].id, array[i].age, array[i].score);
}
// Deallocate!
free(array);
return 0;
}
Enjoy! ^_^
I have some code, but for some reason the location of a variable changes in the middle of my code.
In my main I read one integer from stdin, then malloc an array of structs.
int main(){
int numcities;
scanf("%d", &numcities);
City **cities = malloc(numcities*sizeof(City)*2); //*2 is just to be sure, gonna remove that later.
for(int n = 0;n<numcities;n++){
int nularr[numcities];
for(int n2 = 0;n2<numcities;n2++){
nularr[n2] = 0;
}
City c = {
.value = 1,
.options = nularr,
};
cities[n] = &c;
};
readRoads(cities, numcities);
}
readRoads is shown below. before calling readRoads I can access numcities (gdb and inside the code), but after it sigsegvs when trying to use it, and in gdb complains about not being able to read memory at 0xffffffcd.
If I take a pointer to numcities and dereference it later, everything is intact. but getting the pointer after calling readRoads gives me 0xffffffcd (consistently) which is unreadable.
I already receive twice as much memory from malloc as necessary,
void readRoads(City **cities, int N){
for(int n = 0;n<N;n++){
int buf;
int res[N];
int roads = 0;
City *options[N];
scanf("%d", &buf);
for(int r = 0;r<N;r++){
res[r]= buf << r;
if(res[r]){
options[roads] = cities[r];
roads++;
}
}
cities[n]->id = n;
cities[n]->name = n +'A';
cities[n]->optionsCount = 1;
for(int i = 0; i < roads; i++){
cities[n]->options[i] = options[i]->id;
}
}
}
When you assign to the cities array:
for(int n = 0;n<numcities;n++){
int nularr[numcities];
for(int n2 = 0;n2<numcities;n2++){
nularr[n2] = 0;
}
City c = {
.value = 1,
.options = nularr,
};
cities[n] = &c;
};
You're assigning the address of a local variable. This variable goes out of scope at the end of the for loop, so you end up pointing to invalid memory. Dereferencing this invalid pointer invokes undefined behaivor. The same thing happens when you assign nularr to one of these instances
Rather than create an array of pointers to City, just create an array of City. Also, you'll need to dynamically allocate nularr.
City *cities = malloc(numcities*sizeof(City));
for(int n = 0;n<numcities;n++){
int *nularr = calloc(numcities, sizeof(int);
cities[n].value = 1;
cities[n].options = nularr;
};
Also change readRoads accordingly:
void readRoads(City *cities, int N){
...
And be sure to check the return value of malloc / calloc for errors.
City c = {
.value = 1,
.options = nularr,
};
cities[n] = &c;
}
At this }, c goes out of scope and stops existing (it's a local variable in that block).
The pointer you just saved (cities[n]) has become indeterminate.
Basically, cities is now an array of invalid pointers.
(Also, it should be initialized as
City **cities = malloc(numcities * sizeof (City *));
Specifically, sizeof (City *), not sizeof (City).)
I declared a struct as follows:
struct threadInfo{
char *threadArray[10];
}
Now in main, I create an instance of this struct called t. I also create a different array called sArray[10] and initialize its values to "0".
int main(){
struct threadInfo t;
char *sArray[10];
for (int i = 0; i < 10; i++){
sArray[i] = "0";
}
}
What I am trying to accomplish is that if I modify the threadArray values of the declared struct threadInfo t, then the values of the array sArray should be changed to the values that were modified in threadArray. For example:
t.threadArray[0] = "Changed";
then sArray[0] should be "Changed" as well, but when I print sArray[0] to check if the string becomes "Changed", it is still "0".
I've tried using memcpy to set the struct's threadArray to the sharedArray and then modifying the values of the threadArray but the sharedArray's values stay the same.
memcpy(&(t.threadArray), &sharedArray, sizeof(sharedArray);
for (int j = 0; j < 10; i++){
t.threadArray[i] = "1";
}
How can I set it up so whenever the threadArray values are modified say in a function, the sArray values are modified according to the modified values of threadArray?
When you do
t.threadArray[0] = "Changed";
or
t.threadArray[i] = "1";
you are assigning a new pointer value to a string literal, so the old location
where t.threadArray[i] was pointing to is lost.
If you want to have a link between the variable sArray with threadArray in
the struct, then you have these options
allocate memory for the sArray[i] and assign t.threadArray[i] =
sArray[i]. If you want to modify the contents, then you have to use functions
like strcpy
strcpy(t.threadArray[i], "Changed");
Depending on the the size of the strings, you would need to reallocate the
memory to hold a larger string, so would need to store somewhere the size of the
allocated memory.
Declare struct threadInfo as
struct threadInfo{
char **threadArray;
};
and once again allocate memory for the sArray[i] and the you can do:
t.threadArray = sArray;. But here you would have the same problem with the
size of the buffer.
For example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STRING_LENGTH 15
struct threadInfo{
char **threadArray;
};
void free_sArray(char **arr, size_t len)
{
if(arr == NULL)
return;
for(size_t i = 0; i < len; ++i)
free(arr[i]);
}
int main(void)
{
char *sArray[10] = { NULL }; // initialize all to NULL
for(size_t i = 0; i < sizeof sArray / sizeof sArray[0]; ++i)
{
sArray[i] = calloc(MAX_STRING_LENGTH + 1, 1);
if(sArray == NULL)
{
free_sArray(sArray, i);
return 1;
}
// already 0-terminated because of calloc
sArray[i][0] = '0';
}
struct threadInfo t;
t.threadArray = sArray;
char *words[] = { "this", "is", "a", "verylongandcomplicatedword", "0", "1", "2", "Change" };
// how to change the values
for(size_t i = 0; i < sizeof words / sizeof words[0]; ++i)
{
// here important to use strncpy with size MAX_STRING_LENGTH + 1
// the odds i assign the values through t.threadArray
// the even i assign the values through sArray
// changing the one, changes the other
if(i & 1)
{
strncpy(t.threadArray[i], words[i], MAX_STRING_LENGTH + 1);
t.threadArray[i][MAX_STRING_LENGTH] = 0; // making sure to write \0
} else {
strncpy(sArray[i], words[i], MAX_STRING_LENGTH + 1);
sArray[i][MAX_STRING_LENGTH] = 0; // making sure to write \0
}
}
// how to print
for(size_t i = 0; i < sizeof sArray / sizeof sArray[0]; ++i)
printf("Word %zu: '%s' '%s'\n", i, t.threadArray[i], sArray[i]);
free_sArray(sArray, sizeof sArray / sizeof sArray[0]);
return 0;
}
Which will output
Word 0: 'this' 'this'
Word 1: 'is' 'is'
Word 2: 'a' 'a'
Word 3: 'verylongandcomp' 'verylongandcomp'
Word 4: '0' '0'
Word 5: '1' '1'
Word 6: '2' '2'
Word 7: 'Change' 'Change'
Word 8: '0' '0'
Word 9: '0' '0'
But I don't see the point in doing that, if you want to pass this to a thread,
you can use the same object in the main thread:
struct threadInfo t;
// initialize t
pthread_t th;
pthread_create(&th, NULL, your_thread, &t);
// here if you do
strcpy(t.threadArray[3], "Change");
// the thread will see the change as well
But if you do this, you would have to synchronize the thread with the main
thread and better use a mutex when modifying the contents of threadArray[i].
The code in main could be:
struct threadInfo t;
char **sArray = t.threadArray;
Then sArray[0] indicates the same memory location as t.threadArray[0].
I'm wanting to have my variable houseTot increment by one every time strstr finds a string with "house" in it. I've essentially done this in my code:
struct Owner1_def
{
int totProps;
char type[40];
float monthlyPrice;
float maintenance;
int bedrooms;
int bathrooms;
};
typedef struct Owner1_def Owner1;
int main(void)
{
char *ptr;
int i = 0;
ptr = strstr(database[i].hometype, "house");
for(i = 0; i <= 3; ++i)
{
if (ptr != NULL)
houseTot++;
}
return 0;
}
But when the program prints houseTot's value, it's still at it's initialized value 0. I don't know much about strstr, but from what I've read, this should work.
The call to strstr() should be moved inside the loop so that the value stored in database[i].hometype can be checked on each iteration:
for(i = 0; i <= 3; ++i) {
ptr = strstr(database[i].hometype, "house");
if (ptr != NULL)
houseTot++;
}
Note that posted code has no definition for the array of structs database[], and the struct provided has no hometype field.
I have to read from a file which has a unknown number of students records in it written in binary, then sort the students by their GPA and send to stdout.
Our sort function had to be like
void insertion_sort(Student **, int);
That's why I choose to use an pointer to a pointer to Student (probably not the best solution? I think I could have just sent an pointer to Student like this (&p_to_Student, n) ?)
The code is bellow, the problem is that when I print the first element of what p is pointing to (the first students name) I get gibberish, the other students are fine.
I checked the value of p, and it does change after realloc() is called, and because it's also the address of the first element of p (right?).
Also checked with Valgrind and it returns a bunch of errors about memory leaks!
The code runs fine when there is no realloc() call, also when I initialize p after I'm done reading the file. So it must be something to do with not using realloc() correctly.
Bonus question: is this a proper way to read an unknown number of data entries from a file?
#include <stdio.h>
#include <stdlib.h>
struct student {
char name[30];
char surname[30];
double GPA;
};
typedef struct student Student;
void insertion_sort(Student **arr, int n)
{
int i,j;
for (i=1; i<n; i++)
{
Student *tmp = arr[i];
for (j=i; j>0 && (tmp->GPA > arr[j-1]->GPA); j--)
arr[j] = arr[j-1];
arr[j] = tmp;
}
}
int main(int argc, char **argv)
{
FILE *in;
Student s, *arr, **p;
size_t ret;
int i = 1, n=0, c=2;
in = fopen(argv[1], "rb");
if (in == NULL)
return printf("Can't open file!\n"), 1;
arr = (Student*) malloc(c*sizeof(Student*));
p = (Student**) malloc(c*sizeof(Student*));
do
{
ret = fread(&s, sizeof(Student), 1, in);
if (ret)
{
if (n == c)
{
arr = (Student*) realloc(arr, (c*=2)*sizeof(Student));
p = (Student**) realloc(p, c*sizeof(Student*));
}
// when I print the value of pointer p
// the values is changed when realloc() is called
printf("p = %p\n", p);
arr[n] = s;
p[n] = arr+n;
n++;
}
} while (ret);
fclose(in);
// If I do this instead the program runs correctly
//p = (Student**) malloc(c*sizeof(Student));
//for (int i=0; i<n; i++)
//{
//p[i] = arr+i;
//}
insertion_sort(p, n);
for (i=0; i<n; i++)
{
printf("%2d. %-20s %-20s %7.2lf\n", i+1, p[i]->name,
p[i]->surname, p[i]->GPA);
}
free(arr);
free(p);
return 0;
}
realloc may change the pointer. That means all pointers into that pointer may become invalid. In your case, p holds pointers into arr.
Your problem is not that the value of p changes, but that the old values of p are no longer valid when the value of arr changes.
To illustrate (all pointer and size values are made up):
sizeof(stud) == 16;
allocate arr: arr == 0x00100000;
1st value: arr[0] = stud1; p[0] = &arr[0]; // 0x00100000
2nd value: arr[1] = stud2; p[1] = &arr[1]; // 0x00100010
reallocate arr: arr == 0x00200000;
old address of arr is no longer valid!
3rd value: arr[0] = stud1; p[2] = &arr[2]; // 0x00200020
Now your pointer array looks like this:
p[0] == 0x00100000 // no longer valid!
p[0] == 0x00100010 // no longer valid!
p[0] == 0x00200020 // okay
Because you need p only for your sorting, the approach you have commented out – to allocate p at one go before sorting – is better.
realloc is useful only if you don't now beforehand how big your array is, so you should use it as long as you are building the array. When you are done building the array and you can be sure that arr will stay the same you should create the array of pointers, p.