Swapping Dynamic allocated structures - c

I am trying to swap two structures which are dynamically allocated. But only string(name) is swapping. Anyone can tell me what's wrong with my snippet.
typedef struct
{
char name[20];
int num;
char ch;
}student;
void swap(student **a,student **b)
{
student *temp;
temp = *a;
*a = *b;
*b = temp;
}
void main()
{
student *s;
int i;
s = (student *)malloc(10 * sizeof(student));
printf("enter values: ");
for(i=0;i<10;i++)
scanf("%d %c %s",&s[i].num,&s[i].ch,s[i].name);
swap(s+3,s+4);
printf("\n");
for(i=0;i<10;i++)
printf("%d %c %s\n",s[i].num,s[i].ch,s[i].name);
printf("\n");
}
'

The function swap() gets two parameters of type student **.
However, in the call swap(s+3,s+4);, you pass it two arguments of type student * -- as is the type of s. Could you compile it at all?
Anyway, what you are doing in the swap() function is replacing the content to which each pointer is pointing. That is, if you have had two pointers to students (say: p1, that is pointing to student s1, and p2, that is pointing to student s2), you could have called swap(&p1, &p2) and have them point to the other students (i.e., p1 to s2 and p2 to s1).
But in your main()'s code, you are not dealing with pointers to students. Rather, you try to replace the content of the students themselves -- which is not what swap() does at all.

The are an erron, the pointer refers to same memory location , Try use another student pointer for example declare another student *s2!!!

Related

C adding to struct pointer array doesnt work in function

I have a struct Student. I initialise it inside the main function, and i try to add students inside a function. It doesn't work, but if i put the same code into the main function, it works normally. What am i doing wrong?
struct Student
{
char* name;
};
void addStudent(struct Student *student, int *n)
{
(*n)++;
if(*n != 1)
{
student = realloc(student, (*n) * sizeof(struct Student));
}
printf("Insert name : ");
student[*n-1].name = malloc(25 * sizeof(char));
scanf("%s", student[*n-1].name);
for(int i=0;i<*n;i++)
{
printf("name: %s\n", student[i].name);
}
}
main:
int main() {
int n=0;
struct Student *student = malloc(1 * sizeof(struct Student));
while(1)
{
addStudent(student, &n);
}
}
tl;dr: You need your argument to be of struct Student ** since you are using malloc()/realloc() inside a function.
As you are aware, when an argument is passed in a function, its value is copied so that any changes made inside the function will not be visible to the calling code. We overcome this by passing a pointer to the value we want to modify: we do not change the actual value of our argument, we are only messing with the memory location our pointer argument points to.
In your code, you are reallocating space inside your function, which means that the value of the pointer itself is modified. So, this change is "discarded" after the end of the function and your main never sees the reallocated pointer (note that the allocated space is still "there", meaning that your program takes that resource, you have just no pointer referencing it after the end of your function which is a memory leak).
The solution: make the argument of type pointer to the pointer you want to reallocate, i.e. struct Student **.
The changes you need to do are the following:
void addStudent(struct Student **pstudent, int *n) {
(*n)++;
if(*n != 1){
*pstudent = realloc(*pstudent, (*n) * sizeof(struct Student));
}
(*pstudent)[*n-1].name = malloc(25 * sizeof(char));
scanf("%s", (*pstudent)[*n-1].name);
for(int i=0;i<*n;i++)
{
printf("name: %s\n", (*pstudent)[i].name);
}
}
and in your main() just call your function as:
addStudent(&student, &n);

Trying to pass new values to an array of pointers

I'm trying to create a function for adding 1 element to each of the three pointer arrays (firstArray, lastArray, scoreArray). For this particular assignment, I'm supposed to use pointers and dynamic memory but no structures.
As the program is now, it automatically moves to adding an additional record and waits for all 3 parts of the user input. However, when the program calls the printRecords() function after running the addRecords() function, I get a segmentation fault. I assume this means I'm not passing the changes made in the addRecords() function back to the main therefore, there is nothing stored where the printRecords() function is trying to read. I've tried several times but have gotten nowhere.
How should I alter the 3 problem lines in addRecords() to pass the changes made to the arrays back to the main?
void printRecords(char **firstArray, char **lastArray, float **scoreArray, int n);
void addRecords(char **firstArray, char **lastArray, float **scoreArray, int *j);
int main(int argc, char** argv) {
int i = 0, n = 0;
printf("Please indicate the number of student records to be entered:");
scanf("%d",&n);
char **firstArray;
char **lastArray;
float **scoreArray;
firstArray = (char **)malloc(n*sizeof(char *));
lastArray = (char **)malloc(n*sizeof(char *));
scoreArray = (float **)malloc(n*sizeof(float *));
for(i=0;i<n;i++)
{
printf("Enter Record %d:",i+1);
firstArray[i] = (char *)malloc(n*sizeof(char));
lastArray[i] = (char *)malloc(n*sizeof(char));
scoreArray[i] = (float *)malloc(n*sizeof(float));
scanf("%s",firstArray[i]);
scanf("%s",lastArray[i]);
scanf("%f",scoreArray[i]);
}
addRecords(firstArray,lastArray,scoreArray,&n);
printRecords(firstArray,lastArray,scoreArray,n);
return (EXIT_SUCCESS);
}
void printRecords(char **firstArray, char **lastArray, float **scoreArray, int n)
{
int i = 0;
printf("\nPrinting %d student records....\n",n);
for(i=0;i<n;i++)
{
printf("Record %d: %s - %s - %.2f\n",i+1,firstArray[i],lastArray[i],*scoreArray[i]);
}
}
void addRecords(char **firstArray, char **lastArray, float **scoreArray, int *j)
{
int t = *j; //Assigning current number of records to temp variable
t++; //Increment by 1
*j = t; //Passes the new number of records back to main
printf("Enter Record %d:",t);
firstArray[t] = (char *)malloc(t*sizeof(char));
lastArray[t] = (char *)malloc(t*sizeof(char));
scoreArray[t] = (float *)malloc(t*sizeof(float));
scanf("%s",firstArray[t]); **//PROBLEM LINES**
scanf("%s",lastArray[t]); **//PROBLEM LINES**
scanf("%f",scoreArray[t]); **//PROBLEM LINES**
printf("\nNew record added successfully");
return;
}
I think your memory allocation for the strings is very confused. You have two layers - the arrays of pointers and the actual strings they point to. You are allocating the arrays once at size n. Oddly, the strings are also allocated at size n?? Those should probably be based on some parameter of the problem. In addRecords, you then allocate the added strings at a variable size based on the current number of records but you don't actually extend the arrays of pointers.
Finally, make sure you enforce any length limitations on the strings when you read in the records so you don't trash memory.

C programming Structure Vector allocation

I have a structure in c and I want to allocate memory for an array of my structure,
for this I'd created a function.
The problem is that only first element of array is working.
If I do allocation in main, it is working.
Here is my code:
typedef struct {
int id;
char* name;
}Car;
void read(Car**cars){
int n,i;
char name[50];
printf("Cars:"); scanf("%i",&n);
*cars = (Car*) malloc(n * sizeof(Car));
for(i=0;i<n;i++) {
printf("\nCar Name[%i]: ",i); scanf("%s",name);
(*cars[i]).id = i; //when i>0 then It crash here...
(*cars[i]).name = (char*) malloc(strlen(name)+1);
strcpy((*cars[i]).name, name);
printf("Cars Name -> %s ", (*cars[i]).name);
}
}
int main() {
Car *cars = NULL;
read(&cars);
return 0;
}
what I am doing wrong?
(*cars)[i].id = i; //when i>0 then It crash here...
This should work for you.
explanation:
you allocate n elements to the value of the pointer to the cars pointer.
but you try to derefference the value of the ith pointer to a cars element.
With my correction you derefference the firsts pointer's ith cars id. what is bad coded but should do what you want.
But what you probabbly want to do is asigning multiple pointers which at all point to a single car pointer instead ;)
than your crashing line could stay at it is.

Using qsort to sort structures (sorting by the "last name" field)

I have this part, to begin with (I'll be using it to create employee structures):
typedef struct
{
char first_name[20], last_name[20];
int birthdate, temporary;
//date of birth YEAR/MONTH/DAY
//temporary employees: 1, else 0
}factory;
I will be reading the data using the following function:
void reading(factory *employee,int *nr)
{
++(*nr);
printf("First name:\n");
fflush(stdin);
gets((employee+*nr)->first_name);
printf("Last name:\n");
fflush(stdin);
gets((employee+*nr)->last_name);
printf("Birthdate:\n");
fflush(stdin);
scanf ("%d" , &((employee + *nr)->birthdate));
printf("Temporary employee? 1 for YES, 0 for NO");
fflush(stdin);
scanf("%d", &((employee + *nr)->temporary));
}
And the comparison function (I don't think it's properly written, any suggestions on how to modify it would be great -- should it be "factory employee *ia" instead of struct?):
int struct_cmp_by_name(const void *a, const void *b)
{
struct employee *ia = (struct employee *)a;
struct employee *ib = (struct employee *)b;
return strcmp(ia->last_name, ib->last_name);
}
I also have a simple display function whose prototype I'll copy below:
void display(factory *employee, int nr)
Other portions of code have been omitted for the sake of space. How would I implement the qsort function in this case? I have the comparison function, but I don't know what the base array should be or how to find the other two size parameters. Anticipated thanks for any help provided.
It should be
factory *ia = (factory *)a;
or you could skip the assignments and just cast
... ((factory *)a)->last_name ...
I assume somewhere in your code you allocate or declare space for an array of factory?
For the quick sort, you can either swap the structures, or you can create an array of pointers to structures and swap pointers.

memcpy of structure having pointers as members in C

I have a structure with some pointers as members and I am trying to do memcpy and I have been suggested that I should not use memcpy in this case as memcpy do a shallow copy (meaning it copies pointers) rather deep copy (meaning copying what pointers point to).
But I am not sure why it is not making any difference in the following program:
Please have a look at code and output and please explain why it is not a shallow copy in this case?
#include <stdio.h>
#include <malloc.h>
#include <string.h>
struct student {
char *username;
char *id;
int roll;
};
void print_struct(struct student *);
void print_struct_addr(struct student *);
void changeme(struct student *);
int main (void) {
struct student *student1;
char *name = "ram";
char *id = "200ABCD";
int roll = 34;
student1 = (struct student *)malloc(sizeof(struct student));
student1->username = name;
student1->id = id;
student1->roll = roll;
print_struct_addr(student1);
print_struct(student1);
changeme(student1);
print_struct(student1);
print_struct_addr(student1);
return 0;
}
void print_struct(struct student *s) {
printf("Name: %s\n", s->username);
printf("Id: %s\n", s->id);
printf("R.No: %d\n", s->roll);
return;
}
void print_struct_addr(struct student *s) {
printf("Addr(Name): %x\n", &s->username);
printf("Addr(Id): %x\n", &s->id);
printf("Addr(R.No): %x\n", &s->roll);
return;
}
void changeme(struct student *s) {
struct student *student2;
student2->username = "someone";
student2->id = "200EFGH";
student2->roll = 35;
print_struct_addr(student2);
memcpy(s, student2, sizeof(struct student));
student2->username = "somebodyelse";
return;
}
output:
Addr(Name): 9b72008
Addr(Id): 9b7200c
Addr(R.No): 9b72010
Name: ram
Id: 200ABCD
R.No: 34
Addr(Name): fa163c
Addr(Id): fa1640
Addr(R.No): fa1644
Name: someone
Id: 200EFGH
R.No: 35
Addr(Name): 9b72008
Addr(Id): 9b7200c
Addr(R.No): 9b72010
If memcpy does a shallow copy, how come student1->username is NOT "somebodyelse".
Please explain in which scenario, this code can create problem, I want student2 information in student1 after changeme() call in main() and should be able to use this modified student1 data afterwards.
I have been suggested to NOT to use memcpy() here, but it seems to be working fine.
Thanks
This is the modified code: But still I dont see concept of shallow copy here:
#include <stdio.h>
#include <malloc.h>
#include <string.h>
struct student {
char *username;
char *id;
int roll;
};
void print_struct(struct student *);
void print_struct_addr(struct student *);
void changeme(struct student *);
int main (void) {
struct student *student1;
char *name = "ram";
char *id = "200ABCD";
int roll = 34;
student1 = malloc(sizeof(*student1));
student1->username = name;
student1->id = id;
student1->roll = roll;
print_struct_addr(student1);
print_struct(student1);
changeme(student1);
print_struct(student1);
print_struct_addr(student1);
return 0;
}
void print_struct(struct student *s) {
printf("Name: %s\n", s->username);
printf("Id: %s\n", s->id);
printf("R.No: %d\n", s->roll);
return;
}
void print_struct_addr(struct student *s) {
printf("Addr(Name): %x\n", &s->username);
printf("Addr(Id): %x\n", &s->id);
printf("Addr(R.No): %x\n", &s->roll);
return;
}
void changeme(struct student *s) {
struct student *student2;
student2 = malloc(sizeof(*s));
student2->username = strdup("someone");
student2->id = strdup("200EFGH");
student2->roll = 35;
print_struct_addr(student2);
memcpy(s, student2, sizeof(struct student));
student2->username = strdup("somebodyelse");
free(student2);
return;
}
This:
struct student *student2;
student2->username = "someone";
student2->id = "200EFGH";
student2->roll = 35;
Is writing into non-allocated memory, invoking undefined behavior. You need to make sure student2 is pointing at somewhere valid, before writing.
Either allocate it, or use an on-stack instance since you're just going to copy from it anyway.
Of course, this entire business of initializing student2 and then overwriting s with it is needlessly complicated, you should just modify s directly.
Also, this:
student1 = (struct student *)malloc(sizeof(struct student));
is better written, in C, as:
student1 = malloc(sizeof *student1);
This removes the pointless (and potentially dangerous) cast, and makes sure the size is the proper one for the type, replacing a dependency checked by the programmer with one handled by the compiler.
Thirdly, it's a bit of a classic "symptom" of the beginning C programmer to not realize that you can assign structures. So, instead of
memcpy(s, student2, sizeof *s);
You can just write:
*s = *student2;
And have the compiler to the right thing. This might be a performance win, since the structure can contain a lot of padding which the assignment can be aware of and not copy, but which memcpy() cannot ignore.
That it works at all is a fluke. In your changeme() function you are creating a new pointer for student2, but you are not allocating the memory for it.
Secondly, in that same function you are changing student2 after you've copied it into s.
A shallow copy does not mean that any pointers within the copies are shared - it means that the values of the pointers themselves are also copied. So when you change student2->username after the memcpy it doesn't change the value of s->username.
As you progress, you also need to be more careful with the allocation of memory within those structures. AFAICR, if you use a constant literal string then the pointer will point at a chunk of statically initialised data within the program's memory space. However a more rigourous design would malloc() and free() dynamic memory for those elements. If you ever needed a statically initialised value you would use strdup() or similar to copy the string from the static space into heap memory.
You set the username to "somebodyelse" after copying. And that changes only the local copy inside the function "changeme()". Try printing out student2 inside "changeme()" and you will see what I mean.

Resources