Assign values to a record array in C - c

I've got the following problem. For a homework assignment I'm supposed to create an Heap-Array of the record "student" for 5 students and then assign some values(names etc.).
Now when I try to assign values to the record the way I did it before, i get an "expression expected before {" error.
Edit:
typedef struct student_t {
char hauptfach[128];
char name[64];
int matnr;
} student;
/Edit
student *students;
students = malloc(5*sizeof(student));
students[0] = {"Info", "Max Becker", 2781356};
students[1] = {"Soziologie", "Peter Hartz", 6666666};
students[2] = {"Hurensohnologie", "Huss Hodn", 0221567};
students[3] = {"Info", "Tomasz Kowalski", 73612723};
students[4] = {"Info", "Kevin Mueller", 712768329};
But when I try to assign a single value e.g.
students[0].hauptfach = "Informatik";
the program compiles.
What am I doing wrong?
Thanks in advance,
D.

You haven't shown your structure definition, but I expect that the string is an array of char with some maximum size.
To assign a string, you need to use strncpy. Look that function up.
Basically, assuming that the hauptfach member is MAX_LEN+1 characters long:
strncpy( students[0].hauptfach, "Informatik", MAX_LEN+1 );
students[0].hauptfach[MAX_LEN] = 0; // Force termination if string truncated.
Oops, sorry I misread your question. The above may still hold true.
You cannot copy over a struct like that. You must initialise it at the array definition:
struct mystruct students[5] = {
{"Info", "Max Becker", 2781356},
{"Soziologie", "Peter Hartz", 6666666},
{"Hurensohnologie", "Huss Hodn", 0221567},
{"Info", "Tomasz Kowalski", 73612723},
{"Info", "Kevin Mueller", 712768329}
};
Or you can assign fields individually as you've shown. Another option is you can replace one whole array element like by initialising a single instance and then copying like this:
struct mystruct temp = {"Soziologie", "Peter Hartz", 6666666};
students[0] = temp;

These two statements can't really go together:
1 students = malloc(5*sizeof(student));
2 students[0] = {"Info", "Max Becker", 2781356};
(1) says that you want to dynamically allocate memory at run-time.
(2) says that you want to assign the values you list to a fixed address at compile-time. Unfortunately, the compiler cannot know what the address of students[0] is ahead of time, so it cannot do what you would like.
I'd suggest you create a helper function:
void initstudent(student *s, const char hf[], const char name[], int matnr){
strncpy(s->hauptfach, hf, MAXLEN);
strncpy(s->name, name, MAXLEN);
s->matnr=matnr;
}
and then apply this to each of your students.

Related

Assign values to string array in C

I have a struct that looks like this:
struct persons_s
{
size_t count;
char names[MAX_PERSON_COUNT][MAX_PERSON_NAME_LENGTH];
};
When I try to assign values like this, it does not work:
struct persons_s persons;
persons.count = 2;
persons.names = { "test1", "test2" };
But this works:
struct persons_s persons = { 2, { "test1", "test2" } };
I am assuming this has something to do with the names array being constant, but I'm not sure.
So I'm asking:
What is the exact reason the first way does not work?
Is there a better way to accomplish this?
I also tried
char *names[MAX_PERSONS_COUNT];
but this doesn't work either because I have to use it with strcpy (as destination, strcpy(persons.names[i], source);).
Currently I am doing the assignment like this (using the first struct):
struct persons_s persons;
persons.count = 2;
strcpy(persons.names[0], "test1");
strcpy(persons.names[1], "test2");
You are trying to assign a constant to a pointer (char[][], or **char), in C a string is an array of chars, you can either use strcpy or make it yourself with a for loop.
Your way strcpy(persons.names[0], "test1"); works fine and is probably the best option for you.

employee pay roll taking in info and putting it in array

My program needs to take people's input and calculate salary and withholds and print all of it out. I have the print outs but I'm having trouble storing it in the array.
#include <stdio.h>
#include <stdlib.h>
typedef char *string;
#define MaxEmployees 100
typedef struct {
string name;
string title;
string ssnum;
double salary;
int withholding;
} employeeRecordT;
typedef struct {
string name;
string title;
string ssnum;
double salary;
int withholding;
} *employeeT;
Type: payrollT
This type represents an entire collection of employees. The type definition uses a dynamic array of employeeT values to ensure that there is no maximum bound imposed by the type. The cost of this design is that the programmer must explicitly allocate the storage for the array using NewArray.
typedef struct {
int nEmployees;
employeeT *employees;
} *payrollT;
Global variables
staff -- Array of employees
nEmployees -- Number of employees
manager -- Used to produce a figure for the code
static employeeT staff[MaxEmployees];
static int nEmployees;
static employeeRecordT manager = {
"Ebenezer Scrooge", "Partner", "271-82-8183", 250.00, 1
};
Private function declarations:
static void InitEmployeeTable(void);
static payrollT CreatePayroll(employeeT staff[], int nEmployees);
static void ListEmployees(payrollT payroll);
static double AverageSalary(payrollT payroll);
static void WeeklyPayroll(payrollT payroll);
//static void GetPayroll(void);
static double ssnum(payrollT payroll);
Main program:
int main(void)
{
payrollT payroll;
//GetPayroll(payroll);
InitEmployeeTable();
payroll = CreatePayroll(staff, nEmployees);
ListEmployees(payroll);
WeeklyPayroll(payroll);
}
static void InitEmployeeTable(void)
{
employeeT empRec;
int condition = 1;
int emp_id = 2;
empRec = (employeeT)malloc(sizeof (employeeT));
empRec->name = "Ebenezer Scrooge";
empRec->title = "Partner";
empRec->ssnum = "271-82-8183";
empRec->salary = 250.00;
empRec->withholding = 1;
staff[0] = empRec;
empRec->name = "Bob Cratchit";
empRec->title = "Clerk";
empRec->ssnum = "314-15-9265";
empRec->salary = 15.00;
empRec->withholding = 7;
staff[1] = empRec;
nEmployees = 2;
do {
//malloc(sizeof ());
char name;
char title;
char ssnum;
float salary;
double withholding;
printf("enter name or input stop to quit!\n");
printf("enter first and last name\n");
scanf("%s", empRec->name);
//empRec->name = name;
printf("\nenter title\n");
scanf("%s", empRec->title);
//empRec->title = title;
printf("\nenter social xxx-xx-xxxx\n");
scanf("%s", empRec->ssnum);
//empRec->ssnum = ssnum;
printf("\nenter salary xx.xx\n");
scanf("%lf", &empRec->salary);
//empRec->salary = salary;
printf("\nenter withhodling x\n");
scanf("%d", &empRec->withholding);
//empRec.withholding = withholding;
printf("printed %d", emp_id++);
staff[emp_id] = empRec;
emp_id++;
if (strcmp(empRec->name,"stop") == 1) {
condition = 0;
break;
}
//staff[emp_id]=empRec;
//emp_id++;
} while (condition = 1);
return 0;
}
You aren't allocating storage for any of your strings (name, title, ssnum [in your records, and now that I looked, in your do-while loop too--you can't use char name;, you need e.g. char name[100]; or pointer with malloc]). Using your typedef for string is somewhat hiding that fact. The only time you can assign to a string variable and have the allocation taken care of for you is at declaration time, since the size is known at compile-time e.g.:
char *str = "Hello";
char *str2 = { 'w', 'o', 'r', 'l', 'd', '\0' };
In your case, the assignment of the strings for manager is fine since they are in the initializer, but you still do need to give explicit sizes for the character arrays in your employeeRecordT.
What you need to do is either give explicit sizes for these character arrays or explicitly allocate storage for them (malloc etc.); and instead of assigning, you must use strcpy() (<string.h>) (or strncpy() in cases where overflow is a possibility).
One thing you could do for something like your title variable to save space is to declare a statically allocated list of strings and then just have title be a pointer to the appropriate element in the list, e.g. (the consts are optional, but just makes sure this array doesn't get messed up in any way):
const char const *titles[] = { "Partner", "Clerk", "etc." };
typedef struct {
const char *title;
// ...
} *employeeT;
// ...
empRec->title = titles[0]; // Points title to "Partner"
You could even use an enum as well to help with the index (all of the rest of the code would be the same):
enum { PARTNER, CLERK, ETC };
// ...
empRec->title = titles[CLERK]; // Points title to "Clerk"
Another issue with your code is that you are only allocating storage for a single employeeT record; you can't reuse empRec without calling malloc() again. What is going to happen is every time you change empRec, it's going to change all of the previous staff elements because they all point to the same location (i.e., staff[0] will contain exactly what you set staff[1] to).
Another issue is that you are taking the sizeof (employeeT) but this is wrong since that is only giving you the size of a pointer to your struct. This is one reason why typedefs can make things more confusing. You should create your struct (and typedef to it if you want), but when you need a pointer to it, you should honestly just use the '*' right there in the code (optionally making a second typedef, i.e. typedef struct { // ... } node; typedef node *node_ptr; or even at the same time: typedef struct { // ... } node, *node_ptr;). You have two options, you can either call malloc() again for empRec before you start assigning its members the second (and subsequent) times, or you can simply discard the empRec variable and use staff directly, e.g.:
staff[0] = malloc(sizeof *staff[0]);
// Note I couldn't use employeeT above since you need struct size, not ptr.
// (`sizeof (employeeRecordT)` could have been used though)
strcpy(staff[0]->name, "Ebenezer Scrooge");
// ...
staff[0]->salary = 250.00;
// ...
Be sure to free() every element in staff[] later on.
Furthermore, I don't see why you have this payrollT type which is essentially a copy of your staff array? If you want payrollT you can just have a pointer to an employee record (which by the way, you probably didn't want employeeT *employees;, you probably wanted either employeeT employees; (since it is already a pointer type) or employeeRecordT *employees). I think this is really the only other thing I see wrong with your program snippet.
If you wanted to, you could get rid of your condition variable, and instead of using a do-while loop, just use a while (1) and your break in your if will exit it for you. This way you can be sure it is still evaluated at least once.
By the way, you don't have to cast the return value of malloc(). It's unnecessary since void pointers are safely and automatically promoted to any other type (and vise versa). See here for more info. Also, I see you mention NewArray but never reference it anywhere.

Pass struct array to function with malloc

I'am writing a program where I need to add students to a array of structs.
Well, at the beginning I have the following struct array:
struct student *students[4];
After the declaration I add students like this to the array (just to have examples ...):
students[0] = malloc(sizeof(struct student));
students[0]->firstname = "Max";
students[0]->secondname = "Taler";
students[0]->number = 123456l;
...
Now I have to write a additional function, where I can pass the array as a parameter and add a new student.
So my function looks like this:
void add_student(struct student *students[],char *fristname, char *secondname, long number)
{
int i=0;
int new_position=0;
int return_value = 0;
// Search for the first available position for a new student
for(i=0; i<sizeof(students); i++)
{
if(students[i]==NULL)
{
new_position=i;
return_value = 1;
break;
}
}
struct student *new_student = malloc(sizeof(struct student));
students[new_position] = new_student;
students[new_position]->fristname = fristname;
students[new_position]->secondname = secondname;
students[new_position]->number = number;
return return_value;
}
I call the function with this code:
add_student(students, "Anni", "Karls", 123232);
But now my issue: In my "add_student" function I get an array that has a strange structur: it includes itself as the first element and every other element is shifted by 1 element.
Cant figure out what the problem is ... Can somebody please help?
EDIT: Somebody asked me, how this can be. How the array can include "itself" as the first element.
Well, here are screenshots of the debugger (xCode):
Before entering "add_student":
After entering "add_student" -> IN the function "add_student":
As you see, "students" has now 5 elements ...
Pass the length of the array to the function and change this
for(i=0; i<sizeof(students); i++)
to this
for(i=0; i<arrayLen; i++)
It seems you are inserting an element to some position in an array which has been allocated before hand; inserting is maybe more proper term than adding, but that is opinion.
You were applying sizeof operator on array type inside function - this will likely give you size of pointer in bytes because array name decays to pointer.
It's a little strange to statically allocate the array but then dynamically allocate the individual structures. You might consider dynamically allocating them all:
int num_students = 4;
struct student **students = malloc(sizeof(struct student) * num_students);
And then change your add_student function to look like this:
void add_student(struct student *students[], int arr_size, char *firstname, char *secondname, long number)

how to assign a value to an array element in c language?

#include <malloc.h>
void main()
{
char **variable;
int count=0
variable=(char **)malloc(sizeof(char *)*100);
for(i=0;i<100;i++)
variable[i]=(char *)malloc(sizeof(char)*11);
scanf("%s",variable[count]);
}
Now I want to assign a value to the string present in variable[count]
for example: if variable[count] contains a string "abc" then i want to assign 20 to abc
and if i use printf("%d",abc) then it should print 20
Here
variable=(char **)malloc(sizeof(char)*100);
you want to allocate pointers, so specifiy the correct size of a pointer, that is char*, like so:
variable = malloc(100 * sizeof(char*));
or even better like this:
variable = malloc(100 * sizeof(*variable));
Btw: In C there is not need to cast the results of malloc/calloc/realloc, nor is it recommended.
Following the rules/advices above, this line
variable[i]=(char *)malloc(sizeof(char)*11);
should better look like this
variable[i] = malloc(11 * sizeof(*variable[i]));
Finally this call is dangerous:
scanf("%s",variable[count]);
as it tends to overflow variable[count], so make it save by telling scanf() how much so scan in as a maximum, by doing so:
scanf("%10s", variable[count]); /* Leave one (10=11-1) spare for the C-"string"'s 0-terminator. */
And it's
int main(void)
The type of variable is char **, then variable should point to a list of char *, not a list of char.
Therefore, variable=(char **)malloc(sizeof(char)*100); should be variable=(char **)malloc(sizeof(char *)*100);.
BTW, the type-casting before malloc() is unnecessary.
Now I want to assign a value to the string present in variable[count] for example: if variable[count] contains a string "abc" then i want to assign 20 to abc and if i use printf("%d",abc) then it should print 20
You want to treat the value of variable[count] to be a variable. Unfortunately, you cannot do that. C is a static programming language, which means you cannot create variable on run time, as you do in dynamic programming language.
But C is powerful enough to let you simulate this. You could create a look-up table, such as
typedef struct var {
char *name;
int val; /* or whatever type you want */
} var_t;
var_t variable[num_of_vars]; /* or whatever data structure that you can search */

Changing values in elements of an array of structs

I am working on an assignment and ran into challenging problem. As far as I'm concerned and from what I've learnt the code that follows should be correct however it does not work. Basically what I am trying to is copy a string value into the variable member of a structure the is part of an array passed into a method as a pointer. What am I missing?
typedef struct
{
char * name; //variable in struct I am trying to access
} Struct;
void foo(Struct * arr) //array of Structs passed into function as a pointer
{
int i = 0;
while(i++ < 2)
{
arr[i].name = malloc(sizeof(char *)); //assigning memory to variable in each Struct
arr[i].name = strdup("name"); //copying "name" to variable in each Struct
printf("C - %s\n", arr[i].name); //printing out name variable in each Struct
}
}
main()
{
Struct * arr; //defining pointer
arr = calloc(2, sizeof(Struct)); //allocating memory so pointer can hold 2 Structs
foo(arr); //calling function foo passing pointer into function
return 0;
}
This code compiles and runs however it does not do what it is designed to do. Forgive me if it is something trivial. I am new to the language C
Two issues:
while(i++ < 2) This line changes the value of i as soon as it checks it, so your loop body will not be the same as it was checked.
arr[i].name = strdup("name"); overwrites the value of the .name pointer, causing a memory leak of the memory you malloc()'ed earlier.
Extending on 2 pointed out correctly already,
arr[i].name = strdup("name");
Even if you use following instead of above,
strcpy(array[i].name, "name");
you haven't allocated enough bytes to store the string i.e. this is wrong
arr[i].name = malloc(sizeof(char *));
// even if pointer is 8 byte here, concept isn't right
Should be something like
arr[i].name = malloc(strlen("name")+1);
// or MAX_SIZE where it is greater than the possible "name".
Or better yet, remove the malloc at all, strdup takes care of allocation itself
This is not answering your question directly, but addresses an issue to big to put into a comment...
Additional issue: You probably did not intend to allocate only a (char *) worth of memory to a variable intended to hold at least "name". Change;
arr[i].name = malloc(sizeof(char *));
to:
arr[i].name = malloc(sizeof(char)*strlen("name")+1); //+1 for '\0'
or better yet, use char *name="name";, then:
arr[i].name = malloc(sizeof(char)*strlen(name)+1);
Even more general (and better):
char *name;
name = malloc(strlen(someInputString)+1);
//do stuff with name...
free(name);
Now, you can allocate name to any length needed based on the length of someInputString.
[EDIT]
Etienz, I wanted to address one more thing, alluded to by #H2CO3 above, but not really explained, that I think might be useful to you:
Regarding your desire to have room for two structs, because you typedef'd your struct, you can simply do something like this: (but I am going to change the name you used from Struct to NAME :) The whole point being that when a struct is created as an array, you do not need to use calloc or malloc to create space for them, it is done as shown below...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
char *name;
}NAME;
//use new variable type NAME to create global variables:
NAME n[2], *pN; //2 copies AND pointer created here
//prototype func
int func(NAME *a);
int main()
{
pN = &n[0]; //pointer initialized here
func(pN); //pointer used here (no malloc or calloc)
printf("name1 is %s\nname 2 is %s", pN[0].name, pN[1].name);
return 0;
}
int func(NAME *a)
{
char namme1[]="andrew";
char namme2[]="billebong";
//You DO have to allocate the members though
a[0].name = malloc(strlen(namme1)+1);
a[1].name = malloc(strlen(namme2)+1);
strcpy(a[0].name, namme1);
strcpy(a[1].name, namme2);
return 0;
}

Resources