Am I using structs in the wrong way? - c

I have come across this wierd and mysterous (at least to me) error that I am finding a very hard time finding. It gives me an error at the line where I call my function input(student_list1[MAX], &total_entries); where the compiler says:
incompatible type for agument 1 in 'input'
What am I doing wrong here? I sense it something very simple and stupid but I have gone through the code several times now without any avail.
#define MAX 10
#define NAME_LEN 15
struct person {
char name[NAME_LEN+1];
int age;
};
void input(struct person student_list1[MAX], int *total_entries);
int main(void)
{
struct person student_list1[MAX];
int total_entries=0, i;
input(student_list1[MAX], &total_entries);
for(i=0; i<total_entries; i++)
{
printf("Student 1:\tNamn: %s.\tAge: %s.\n", student_list1[i].name, student_list1[i].age);
}
return 0;
} //main end
void input(struct person student_list1[MAX], int *total_entries)
{
int done=0;
while(done!=1)
{
int i=0;
printf("Name of student: ");
fgets(student_list1[i].name, strlen(student_list1[i].name), stdin);
student_list1[i].name[strlen(student_list1[i].name)-1]=0;
if(student_list1[i].name==0) {
done=1;
}
else {
printf("Age of student: ");
scanf("%d", student_list1[i].age);
*total_entries++;
i++;
}
}
}

struct person student_list1[MAX] in the function argument is actually a pointer to struct person student_list1.
student_list1[MAX] you passed is a (out of bound) member of the array struct person student_list1[MAX]. Valid array index shoudl be between 0 to MAX - 1.
Change it to:
input(student_list1, &total_entries);
Note that here the array name student_list1 is automatically converted to a pointer to student_list1[0].

There are many things wrong with the code; this is my attempt at making it somewhat more robust:
#include <stdio.h>
#include <string.h>
#define MAX 10
#define NAME_LEN 15
// use a typedef to simplify code
typedef struct person {
char name[NAME_LEN];
int age;
} person_t;
// size qualifier on student_list is redundent and person_t* does the same
void input(person_t *student_list, int *total_entries);
int main(void)
{
person_t student_list[MAX];
int total_entries, i;
// pass array and not the non-existent 'student_list[MAX]' element
input(student_list, &total_entries);
for(i=0; i<total_entries; i++)
{
// age is an int, not a string so use %d
printf("Student 1:\tName: %s.\tAge: %d.\n", student_list[i].name, student_list[i].age);
}
return 0;
} //main end
void input(person_t *student_list, int *total_entries)
{
int done = 0, i = 0;
*total_entries = 0;
while (i < MAX) {
printf("Name of student: ");
// use NAME_LEN instead of strlen(list[i].name) because latter is
// probably not initialized at this stage
if (fgets(student_list[i].name, NAME_LEN, stdin) == NULL) {
return;
}
// detect zero-length string
if (student_list[i].name[0] == '\n') {
return;
}
printf("Age of student: ");
scanf("%d", &student_list[i].age);
// read the newline
fgetc(stdin);
*total_entries = ++i;
}
}

input(student_list1[MAX], &total_entries); shoud be input(student_list1, &total_entries);.
In C,
void input(struct person student_list1[MAX], int *total_entries);
equals
void input(struct person *student_list1, int *total_entries);

Related

How to allocate a struct dynamically in C to avoid a segmentation fault?

I'm having a problem to allocate a structure dynamically.
I'm making a program that works as a contact book, but I'm getting the
following error: Segmentation fault (core dumped).
The structure declaration, following the functions to add a contact
and print all contacts:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct contact{
int number;
char name[80];
}contact;
void addContact(contact **contacts, int position){
int aux=position;
printf("Enter the name: ");
setbuf(stdin, 0);
fgets(contacts[position]->name,80,stdin);
printf("Enter the telephone number: ");
scanf("%d",&contacts[position]->number);
return;
}
void printAllContacts(contact **contacts, int size){
for(int i;i<size;i++){
printf("Contact %d:\n",i);
printf("Name: %s\n",contacts[i]->name);
printf("Telephone number: %d \n",contacts[i]->number);
}
}
// Main function:
int main(){
int size;
printf("Enter the list size: ");
scanf("%d",&size);
contact *contacts= (contact*)malloc(sizeof(contact)*size);
int counter=0;
int x;
do{
printf("------------MENU-----------\n");
printf("1-Add contact\n");
printf("2-Print contacts list\n");
printf("0-Exit\n");
printf("----------------------------\n");
printf("Enter an option: ");
scanf("%d",&x);
switch (x){
case 1:
addContact(&contacts,counter);
counter++;
break;
case 2:
printAllContacts(&contacts,counter);
break;
case 0:
break;
}
}while(x!=0);
return 0;
}
Can anyone help?
The basic problem is that you're allocating an array of struct contact objects, but your addContact and printAllContacts expect an array of pointers to struct contact. You need to choose one or the other.
The easiest fix is probably to change the functions -- change the argument type to contact * instead of contact **, remove the & at the call site in main, and change the -> to . in the functions where needed.
Pass in a pointer (contacts *) instead of pointer to pointer (contacts **) to addContact() & printAllContacts(). Updated caller, and partially updated called code which already assumed it was operating on an array.
Initialize i in printAllContacts().
Removed the unnecessary cast of malloc() return value.
Removed the name of the struct as you use only use the typedef.
Introduced a NAME_LEN macro instead of the magic 80 value.
Minor reformatting for readability & consistency.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NAME_LEN 80
typedef struct {
int number;
char name[NAME_LEN];
} contact;
void addContact(contact *contacts, int position) {
printf("Enter the name: ");
setbuf(stdin, 0);
fgets(contacts[position].name, NAME_LEN, stdin);
printf("Enter the telephone number: ");
scanf("%d", &contacts[position].number);
return;
}
void printAllContacts(contact *contacts, int size) {
for(int i=0; i<size;i++) {
printf("Contact %d:\n", i);
printf("Name: %s\n", contacts[i].name);
printf("Telephone number: %d\n", contacts[i].number);
}
}
int main() {
int size;
printf("Enter the list size: ");
scanf("%d", &size);
contact *contacts = malloc(sizeof(contact)*size);
int counter=0;
int x;
do {
printf("------------MENU-----------\n");
printf("1-Add contact\n");
printf("2-Print contacts list\n");
printf("0-Exit\n");
printf("----------------------------\n");
printf("Enter an option: ");
scanf("%d", &x);
switch (x) {
case 1:
addContact(contacts, counter++);
break;
case 2:
printAllContacts(contacts, counter);
break;
case 0:
break;
}
} while(x!=0);
return 0;
}
I would add additional structure holding all the contacts and also keeping the number of contacts stored. You do not need to know the size of the list - it will grow with any added contact.
When you test the idea I would advise you to not use user input functions, only fixed data. It makes debugging and testing faster and easier. Especially function which adds data should not communicate with the external world. Caller is the correct place to do it
Also use function return values to return result or status codes. You tend to use void everywhere - it is not a good idea.
typedef struct contact{
unsigned number;
char name[80];
}contact;
typedef struct
{
size_t size;
contact contacts[];
}constactList;
constactList *addContact(constactList *list, const char *name, const unsigned number)
{
size_t newsize = list ? list -> size + 1 : 1;
list = realloc(list, sizeof(*list) + sizeof(list -> contacts[0]) * newsize);
if(list)
{
strncpy(list -> contacts[list -> size].name, name, sizeof(list -> contacts[0].name));
list -> contacts[list -> size].name[sizeof(list -> contacts[0].name) - 1] = 0;
list -> contacts[list -> size].number = number;
list -> size = newsize;
}
return list;
}
void printContacts(const constactList *list)
{
if(list)
{
for(size_t i = 0; i < list -> size; i++) printf("[%3zu] %s, %u\n", i, list -> contacts[i].name, list -> contacts[i].number);
}
}
int main(void)
{
constactList *list = NULL;
list = addContact(list, "James Bond", 7);
if(!list) {/* error handling*/}
list = addContact(list, "Mata Hari", 99);
if(!list) {/* error handling*/}
list = addContact(list, "Wladymir Putin", 666);
if(!list) {/* error handling*/}
printContacts(list);
free(list);
}

Why does printing from this struct give a segmentation fault?

I'm trying to create an array of Product structs and then print the name and code of each Product in the array, but I keep getting a segmentation fault. I have tried to insert each value without a loop and then printing, and it works, but I'd like to automate it. The function fill_products fills the products array according to the user's input, and the select_products prints each name-code pair for the entire array.
This is my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int code;
char *name;
float price;
} Product;
void select_products(Product *products, int len)
{
int i;
printf("%-30s%s\n", "Name", "Code");
for (i = 0; i < len; i++)
{
printf("%-30s%d\n", products[i].name, products[i].code);
}
return;
}
void fill_products(Product *products, int len)
{
int i, code;
char *name;
float price;
for (i = 0; i < len; i++)
{
printf("Insert product name (%d / %d): ", i + 1, len);
scanf("%s", &name);
printf("Insert product price (%d / %d): ", i + 1, len);
scanf("%f", &price);
products[i].code = i;
products[i].name = name;
products[i].price = price;
}
return;
}
int is_alloc(Product *products)
{
if (products == NULL)
{
printf("Error: memory allocation unsuccessful.\n");
}
return products != NULL;
}
int main(void)
{
int len, n_bytes;
Product *products;
printf("Insert length of array: ");
scanf("%d", &len);
n_bytes = sizeof *products * len;
products = malloc(n_bytes);
if(!is_alloc(products))
{
exit(0);
}
fill_products(products, len);
select_products(products, len);
free(products);
return 0;
}
I keep getting a segmentation fault.
Please enable compiler warnings, and pay attention to them.
This code:
char *name;
...
scanf("%s", &name);
is bogus and doesn't do at all what you intend.
You must either allocate space for name separately (and then not forget to free() it), or make that space available in the Product structure like so:
typedef struct
{
int code;
char name[100];
float price;
} Product;
(this assumes there is a reasonable limit on name length).

Problems with C structs and int variables

#include <stdio.h>
#include "struct.h"
#define NUM 3
struct Student
{
char name[20];
int age;
};
int main(void)
{
struct Student s_array[NUM];
for(int i=0;i<NUM;i++)
{
printf("name: ");
scanf("%s",s_array[i].name);
printf("age: ");
scanf("%i",s_array[i].age);
}
for(int i=0;i<NUM;i++)
{
printf("%s is %i years old",s_array[i].name,s_array[i].age);
}
return 0;
}
I don't know what's the problem I declared an array of structs of type student and used a for loop to initialise their fields, but when I type in the age it gives me segmentation fault. why is that??
struct.c:17:20: warning: format specifies type 'int *' but the argument has type 'int' [-Wformat]
scanf("%d",s_array[i].age);
The int in the struct is an int, not a pointer to an int. Arrays can be assigned directly to pointers, but on other types, you need to apply the addressof (&) operator. Instead of saying "s_array[i].age", say "&(s_array[i].age)".
I worked out this code for you
#include < stdio.h>
#include < stdlib.h>
#define NUM 3
struct Student
{
char name[20];
int age;
};
int main(void)
{
struct Student s_array[NUM];
for(int i=0;i<NUM;i++)
{
printf("name: ");
scanf("%s",&s_array[i].name);
printf("age: ");
scanf("%d",&s_array[i].age);
}
for(int i=0;i<NUM;i++)
{
printf("%s is %d years old",s_array[i].name,s_array[i].age);
}
return 0;
}
#include<stdio.h>
//#include "struct.h>
#define NUM 3
struct Student
{
char name[20];
int age;
};
int main(void)
{
struct Student s_array[NUM];
for(int i=0;i<NUM;i++)
{
printf("name: ");
scanf("%s",&s_array[i].name);
printf("age: ");
scanf("%d",&s_array[i].age);//You sud use "&"operator to take input
}
for(int i=0;i<NUM;i++)
{
printf("%s is %d years old",s_array[i].name,s_array[i].age);
}
return 0;
}

Why am I getting garbage value after displaying the data

I am getting garbage value when I display the records.
I have to create a database of students in C using array of structures and without pointers.
Is there any other way of doing this?
How to use array of structures?
#include <stdio.h>
struct student {
char first_name[10],last_name[10];
int roll;
char address[20];
float marks;
};
void accept(struct student);
void display(struct student);
void main() {
struct student S[10];
int n, i;
printf("Enter the number of records to enter : ");
scanf("%d", &n);
for (i = 0; i < n; i++) {
accept(S[i]);
}
for (i = 0; i < n; i++) {
display(S[i]);
}
}
void accept(struct student S) {
scanf("%s", S.first_name);
scanf("%s", S.last_name);
scanf("%d", &S.roll);
scanf("%s", S.address);
scanf("%f", &S.marks);
}
void display(struct student S) {
printf("\n%s", S.first_name);
printf("\n%s", S.last_name);
printf("\n%d", S.roll);
printf("\n%s", S.address);
}
Everything in C is pass-by-value. Which means you are modifying variable copy in stack frame, while real variable passed as parameter remains untouched.
You have to pass an pointer to variable which you want to modify in function.
// Function declaration
void accept(struct student *);
// Call
accept(&S[i]);
// Usage in function via dereference operator
scanf("%s",S->first_name);
If you would like to enter unknown amount of records, you should use VLA (since c99) or dynamically allocate structures.
VLA
scanf("%d",&n);
struct student S[n];
Dynamic callocation
scanf("%d",&n);
struct student * S = malloc(sizeof(struct student) * n);
Because in your case, if user input more that 9 records you are touching outside of bounds, which has undefined behavior.
There are multiple issues in your code:
The standard prototype for main without arguments is int main(void)
You should allocate the array dynamically with calloc.
you should pass structure pointers to the accept and display functions instead of passing structures by value. Passing the destination structure by value is incorrect as the accept function cannot modify the structure in the main function, which remains uninitialized and causes garbage to be displayed. Note that it is actually undefined behavior to access uninitialized data so the program could behave in even worse ways.
You should provide scanf() with the maximum number of arguments to store into character arrays to avoid potential buffer overflows.
you should verify the return values of scanf() to avoid undefined behavior on invalid input.
you could use the %[^\n] scan set to allow embedded spaces in the address field.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
struct student {
char first_name[10], last_name[10];
int roll;
char address[20];
float marks;
};
void accept(struct student *sp);
void display(const struct student *sp);
int main(void) {
struct student *S;
int n, i, j;
printf("Enter the number of records to enter : ");
if (scanf("%d", &n) != 1)
return 1;
S = calloc(sizeof(*S), n);
if (S == NULL) {
return 1;
}
for (i = 0; i < n; i++) {
accept(&S[i]);
}
for (i = 0; i < n; i++) {
display(&S[i]);
}
free(S);
return 0;
}
void accept(struct student *sp) {
if (scanf("%9s%9s&d %19[^\n]%f",
sp->first_name, sp->last_name, &sp->roll,
sp->address, &sp->marks) != 5) {
printf("missing input\n");
exit(1);
}
}
void display(const struct student *sp) {
printf("%s\n", sp->first_name);
printf("%s\n", sp->last_name);
printf("%d\n", sp->roll);
printf("%s\n", sp->address);
printf("%f\n", sp->marks);
printf("\n");
}

How to search on struct char c?

#include<stdio.h>
#include<stdlib.h> //libraries
#include<string.h>
#define ARRAY_SIZE 4 //define the array size is 4
Declare a Person structure containing the following two data members: name and age.
struct Person
{
char name[20];
int age;
};
Define fillPersons function that takes an empty array of Persons, and fills the array.
void fillPersons(struct Person * myPs);
For function using
struct Person p[ARRAY_SIZE];
Define searchPerson function that takes an array of Persons, and the name to search for. The function will return the corresponding age if the person is found, -1 otherwise.
int searchPerson(struct Person * myPs, char * myName);
Define printPersons function that takes an array of Persons, and prints the content of the array.
void printPersons(struct Person * myPs);
Main Fuction
int main()
{
struct Person p[ARRAY_SIZE];
int a;
int isFound;
char myName[20];
Switch case for user interface
do
{
printf("1)FILL ARRAY\n");
printf("2)SEARCH BY NAME\n");
printf("3)PRINT ARRAY\n");
printf("4)EXIT\n");
printf("Search Operation:");
scanf_s("%d", &a);
switch (a)
{
case 1:fillPersons(p); break;
I write the main part of searching but i cant fill the function.
case 2:printf("\Give the name to search for:");
scanf_s("%s", &myName);
isFound = searchPerson(p, myName);
if (isFound == -1)
{
printf("%s not avaible in the array. \n", myName);
}
else
{
printf("The age of %s is %d.\n", myName, isFound);
}
break;
After this part it is okay to read names and ages but cant do it searching part.
case 3:printPersons(p); break;
case 4:printf("\nProgram exits ..."); exit(0);
}
} while (a != 4);
system("pause");
return 0;
}
It is okay this scanf part
void fillPersons(struct Person * myPs)
{
int i;
for (i = 0; i < 4; i++)//defining 4 person i<4
{
scanf_s("%20s", p[i].name,_countof(p[i].name));//if i dont do _coutof
scanf_s("%d", &p[i].age); // i get null.ptr error
} // on visiual studio
}
Printing the student names and ages
void printPersons(struct Person * myPs)
{
int i;
for (i = 0; i < 4; i++)
{
printf("%s %d", p[i].name, p[i].age);
}
}
But i dont know how to fill with inside on fuction?
int searchPerson(struct Person * myPs, char * myName)
THE OUTPUT SHOULD BE LIKE THIS
Seems the function you are missing is strcmp to compare two strings.
It could be like:
int searchPerson(struct Person * myPs, char * myName)
{
int i;
for (i = 0; i < ARRAY_SIZE; i++)
{
if (strcmp(myPs[i].name, myName) == 0)
{
return myPs[i].age;
}
}
return -1;
}
In general notice:
When you pass the array to a function as struct Person * myPs, you must use myPs inside the function. Further you should use the defined array size instead of hard coding a 4.
So your printPersons should be:
void printPersons(struct Person * myPs)
{
int i;
for (i = 0; i < ARRAY_SIZE; i++)
{
printf("%s %d", myPs[i].name, myPs[i].age);
}
}
Same applies to fillPersons
First thing, you put in your question all the functions except the one that is giving you problems: searchPerson.
Then, your error is with this instruction:
scanf_s("%s", &myName);
Accordingly that you declared myName as a char pointer, this way, you're assigning the string to the address of myName, not to the memory cells it's pointing to.
Instead, this should be:
scanf_s("%s", myName);

Resources