C programming Structure Vector allocation - c

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.

Related

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.

Swapping Dynamic allocated structures

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!!!

How to walk through array of Struct in c

I have a program which creates an array or struct and go through it for processing. Initially it initialize the array with the defined nyumber of elements. Then for some number of element in array, the name is assigned.
I pretend the code that is equal to my scenario which is tested in codebloc and get the similar error. The problem is described in comments.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct _car {
char *name;
int year;
} Car;
char *getCarName(char *name, int var);
void processCar();
void printCars(Car car[]);
int INCREMENT = 10;
int main(void)
{
processCar();
return 0;
}
void processCar()
{
// create car array with amount of INCREMENT
Car CAR_ARRAY[INCREMENT];
int a=0;
// This function assign name for Car amount 10 less than INCREMENT
while (a<INCREMENT - 2) {
char *carName;
carName = getCarName(&carName, a);
CAR_ARRAY[a].name = malloc(strlen(carName) + 1);
strcpy(CAR_ARRAY[a].name, carName);
a++;
}
printCars(CAR_ARRAY);
}
void printCars(Car car[])
{
printf("IN Car \n");
int a = 0;
// when try to call name for car amount equals to INCREMENT program terminates.
while(a<INCREMENT) {
if (car[a].name != NULL) // checking if NULL
printf("Car Name : %d -> %s\n", a, car[a].name);
a++;
}
}
char *getCarName(char *name, int var)
{
name = "Toyota";
return name;
}
What is the right way to check the struct value on struct array whether it can be called?
EDIT
I created a hack to do this as follows.
// added these right after creating array
for (a = 0; a < INCREMENT; a++)
CAR_ARRAY[a].name = NULL;
I dont know if it is a standard way or not. pls advice.
You are checking for NULL before printing, which is a good idea, but it doesn't help you here, because your last two cars are uninitialised and likely contain garbage: The name pointer is not NULL, but doesn't point to a valid address either. Segmentation violation ensues.
You should initialise all cars, not only INCREMENT - 2. Alternatively, you could initialise your cars to zero by calling memset before your initialisation:
memset(CAR_ARRAY, 0, sizeof(Car) * INCREMENT);
As an aside, the way you deal with getCarName is rather shaky as well. At the moment, your name is a pointer to a string literal. Your local variable carName does a half-hearted double duty: You try to pass it by reference (but essentially you don't) and you also return it.
Basically, you could do this in one of two ways. The easier one here is to return a pointer. in that case, you don't have to pass any string:
char *getCarName(int var)
{
static char *names[3] = {"Toyota", "Dodge", "Peugeot"};
return names[var % 3];
}
and call it like so:
char *carName = getCarName(&carName, a);
Alternatively, you could pass a char pointer by reference, i.e. as pointer to pointer to char. In that case, you don't have to return anything:
void getCarName(char **name, int var)
{
static char* names[3] = {"Toyota", "Dodge", "Peugeot"};
*name = names[var % 3];
}
Call it like so:
char *carName;
getCarName(&carName, a);
There are other scenarios here, for example if you just pass a char pointer and have getCarName fill it, but I'll leave that for now - it would make everything even more complicated.

Checking NULL for array of structures

struct student
{
int roll;
char *name;
};
int main()
{
int i;
struct student arr[2];
arr[0].roll = 12;
arr[1].name = "John";
arr[1].roll = 13;
arr[1].name = "Craig";
struct student *ptr;
ptr=arr;
// This is perfect.
for(i = 0; i<2; i++)
{
printf("%d %s", ptr->roll, ptr->name);
}
// This is also ok.
printf("%d %s", ptr->roll, ptr->name);
ptr++ // getting to next structure.
printf("%d %s", ptr->roll, ptr->name);
// But this isn't ok
while(*ptr || ptr->name != NULL)
{
ptr++;
}
return 0;
}
How to check pointer in while loop?
ptr points to an array if you increment it, ptr start pointing to a memory out size array that is not null.
You can do something like:
ptr = arr;
while (ptr < (arr + sizeof(arr)/sizeof(arr[0])) ){
ptr++;
}
Note: this technique will nnot work for dynamic arrays.
To learn what is this formula about read: Weird behavior when printing array in C?
You can use ptr check for null if you traversing an array of pointers AND when you know that the end of such array is marked with NULL. You are not.
You actually are traversing an array of structures with the ptr pointing straight to the memory location of the first element.
You have to keep track of the size of the array (or amount of its filled elements) and just stop after you have gone through them all.
int count = 2;
struct student arr[count];
struct student* ptr = arr;
for (int i=0; i<count; i++) {
// do your stuff
ptr++; // place it in for if you like
}
You can use this:
struct student *ptr=arr;
int max_len = sizeof(arr)/sizeof(*arr);
while(max_len--)
{
//do something...
ptr++;
}
One more thing I want to point out is you need to allocate memory for the char* pointer before allocating it with a string.The last loop which you have written doesn't execute at all, since all are NULL pointers.
Other way around is to put some special value in the roll number(say a negative value) of the last struct in the array. You then traverse the array until the roll number is positive.
Note that this method can also be used for dynamic arrays.
struct student *arr = (struct student*)malloc(20*sizeof(struct student));
*(arr+19).roll = -1; //this acts as a sentinel to indicate the end of the array....
struct student *ptr=arr;
while(ptr->roll > 0)
{
//do something...
ptr++;
}
while(*ptr || ptr->name != NULL)
First things first: the value of *ptr is a struct, which can't be converted to a boolean value and so while(*ptr) won't compile.
In order to null-terminate an array of structs, you must choose some struct member which you know will never be NULL when the struct is initialized (usually an important pointer), and use it as the flag. You do have that: the name field.
while(ptr->name != NULL)
Then the only problem is that your array isn't actually NULL terminated. You need to reserve an extra, third element at the end, just like with strings. An easy way to do so is by zero-initializing the whole array at declaration. So:
struct student arr[3] = {0};
arr[0].roll = 12;
arr[0].name = "John";
...
Which would have the same effect as manually setting ar[2].name = NULL;

Trying to copy entire structure to another structure of same type...but getting errors

Hi friends i am trying to copy a entire structure to another structure. When i compile, i don't get errors....when i print displays some garbage value....please guide me...Thanks!
In two different functions i am trying to add values and print it. My first function is "read_list"...in this i am getting the name of the student and marks inserted from the user.
My second functions is "print_list", using this function i am printing the details of student.
Please guide me to a tutorials where i can find few quite interesting examples using structure's in C
#include<stdio.h>
typedef struct _student
{
char name[50];
unsigned int mark;
} student;
void print_list(student list[], int size);
void read_list(student list[], int size);
int main(void)
{
const int size = 3;
student list_first[size]; //first structre
student list_second[size]; //second structre of same type
read_list(list_first, size); //list_first structer fills with values
print_list(list_first, size); //to check i have printed it here
//Now as i knew that my first struct is filled with data .....so now i wanted to copy it
list_second[size] = list_first[size]; //cpoid from one struct to another
printf("Second list is copied from another struct: \n");
print_list(list_second, size); //Tried to print it here ....
system("pause");
return 0;
}
void read_list(student list[], int size)
{
unsigned int i;
printf("Please enter the info:\n");
for(i = 0; i<size; i++)
{
printf("\nname: ");
scanf("%s",&list[i].name);
printf("\nMark: ");
scanf("%d",&list[i].mark);
}
}
void print_list(student list[], int size)
{
unsigned int i;
for(i=0; i<size; i++)
{
printf("Name: %s\t %d\n",list[i].name,list[i].mark);
}
}
Use memcpy() to copy the arrays:
memcpy(list_second, list_first, sizeof(list_first));
The current assignment attempt is incorrect as it is accessing beyond the bounds of the array (arrays have zero based indexes, so valid indexes run from 0 to size - 1) causing undefined behaviour:
list_second[size] = list_first[size];
Even if it was not, it would only copy one of the elements and is the reason garbage is printed because list_second is uninitialized.
list_second[size] = = list_first[size];
is undefined behaviour as the allowed indices to list_second and list_first are 0 to size - 1. So using size as index you try to address the array element behind the last element.
To copy all array members use:
for (size_t sizeCnt = 0; sizeCnt < size, ++ sizeCnt)
{
list_second[sizeCnt] = list_first[sizeCnt];
}
As a note: To access array elements, as well as to address memory the preferred integer type is size_t, which is defined to be an unsigned type to be wide enough to access the platforms address space.
change list_second[size] = list_first[size]; to memcpy(list_second,list_first,sizeof(list_first)); you need to copy an array of structure, not a element. also array[3] means an array of 3 elements. So 2 is the maximum index allowed. array[3] is invalid

Resources