Need help in pure c list implementation - c

I am trying to do linked list of persons in c.
All my methods work in main() until I put them into while loop (for reading commands from user). Everything compiles, but when I try to run it, it crashes returning random values.
Here are parts of my code.
Structure:
struct Person{
const char* name;
const char* sex;
int age;
struct Person* next;
} *head;
Method insert:
void insert(struct Person* h, char*n, char* s, int a){
for(; h->next != NULL; h=h->next){}
struct Person* p = (struct Person*) malloc(sizeof(struct Person));
p->name=n;
p->age=a;
p->sex=s;
p->next=NULL;
h->next=p;
}
and main in which it doesn't work:
int main()
{
struct Person Maciek={"Maciek", "Male", 20, NULL};
head = &Maciek;
int comand = 0;
while(comand != 6){
printf("Choose command:\n 1-insert person \n 2-delete by index \n 3-delete by name \n 4-display by index \n 5-print whole list \n 6-exit\n");
scanf("%d", &comand);
if(comand == 1){
printf("Name, Gender, Age\n");
char* name;
char* sex;
int age;
scanf("%s, %s, %d", &name, &sex, &age);
printf("Name %s, Sex %s, Age %d", name, sex, age);
insert(head, name, sex, age);
}
if(comand == 2){
printf("2\n");
}
if(comand == 3){
printf("3\n");
}
if(comand == 4){
printf("4\n");
}
if(comand == 5){
printf("5\n");
}
}
return 0;
}
I am quite new to C/C++, and I would really appreciate any help.

if(comand == 1){
printf("Name, Gender, Age\n");
char* name;
char* sex;
int age;
scanf("%s, %s, %d", &name, &sex, &age);
Here you are using dangling pointers (which are pointing anywhere in memory), you should use malloc to allocate some memory or use char arrays, and as Carl Norum pointed out you shouldn't have & in your scanf call as you need to provide some char* and not char**. You can do it like this (this code is vulnerable to buffer overflow, don't use that in production code, consider using fgets+sscanf):
char name[50];
char sex[20];
int age = 0;
scanf("%s, %s, %d", name, sex, &age);
In your insert function:
struct Person* p = (struct Person*) malloc(sizeof(struct Person));
p->name=n;
p->age=a;
p->sex=s;
You are replacing p->name with n, instead of copying the content of n into p->name. You want:
struct Person *p = malloc(sizeof(struct Person));
p->name = malloc(strlen(n)+1);
if(p->name == NULL) {
//error handling...
}
strcpy(p->name, n);
p->sex = malloc(strlen(s)+1);
if(p->sex == NULL) {
//error handling...
}
strcpy(p->sex, s);
p->age = a;

You're reading strings into pointers that have not been initialized with allocated memory.

Related

Weird characters in string with C (Structs, pointers, and strings)

Hi I'm creating a linked list that holds students' information.
However, when displaying the string variables of the student struct, it displays characters other than the strings that it's supposed to display. Here is the snippet from my code (I cut out the code unrelated to my problem):
# include <stdio.h>
# include <stdlib.h>
struct Student {
int student_number[2];
char *last;
char *first;
char *course;
int year;
int age;
char sex;
int grade;
struct Student * next;
};
typedef struct Student Student;
struct SLList {
Student * head;
Student * tail;
int size;
};
typedef struct SLList SLList;
void initList(SLList * list){
list->head = 0;
list->tail = 0;
list->size = 0;
}
Student * getStudent(SLList * list, int index) {
Student * current = list->head;
for (int i = 0; i < index; i ++) {
current = current->next;
}
return current;
}
Student * createStudent(int * number, char *last, char *first, char * course, int year, int age, char sex, int grade){
Student * student = (Student *) malloc(sizeof(Student));
student->student_number[0] = number[0];
student->student_number[1] = number[1];
student->last = last;
student->first = first;
student->course = course;
student->year = year;
student->age = age;
student->sex = sex;
student->grade = grade;
student->next = 0;
return student;
}
void enrolStudent(SLList * list, int index){
Student * student;
int i, found = 1;
int student_number[2];
char last[15];
char first[15];
char course[15];
int year;
int age;
char sex;
int grade;
printf("Student Number: ");
scanf("%i-%i", &student_number[0], &student_number[1]);
printf("Last Name: ");
scanf("%s", last);
printf("First Name: ");
scanf("%s", first);
printf("Course: ");
scanf("%s", course);
printf("Year: ");
scanf("%i", &year);
printf("Age: ");
scanf("%i", &age);
printf("Sex [M or F]: ");
scanf(" %c", &sex);
printf("Final Grade: ");
scanf("%i", &grade);
Student * toInsert = createStudent(student_number, last, first, course, year, age, sex, grade);
if (index == 0){
toInsert->next = list->head;
list->head = toInsert;
}
if (index == list->size){
if (list->tail != 0) {
list->tail->next = toInsert;
}
list->tail = toInsert;
}
list->size ++;
return;
}
void showStudents(SLList * list, int index) {
Student * student = getStudent(list, index);
printf("\n");
printf("Student Number: %i-%i\n", student->student_number[0], student->student_number[1]);
printf("Last Name: %s\n", student->last);
printf("First Name: %s\n", student->first); //! error in printing strings
printf("Course: %s\n", student->course);
printf("Year Level: %i\n", student->year);
printf("Age: %i\n", student->age);
printf("Sex: %c\n", student->sex);
printf("Final Grade: %i\n", student->grade);
printf("\n");
}
int main(){
int choice = 0;
int rtn = 0;
SLList students;
initList(&students);
printf("What do you want to do?\n");
printf("1. Enrol a student\n");
[...]
printf("4. Display all student/s\n");
for(;;){
printf("\nEnter a number: ");
rtn = scanf("%d", &choice);
if (choice == 1) {
enrolStudent(&students, students.size);
} else if (choice == 4) {
int i;
for (i = 0; i < students.size; i ++){
showStudents(&students, i);
}
printf("Displaying %i of %i student(s)\n", i, students.size);
}
[...]
}
I believe that I need to allocate memory for the char * variables of the struct, but I don't know how it should go.
Hope to get some help. Thanks!
you are passing local variable address to createStudent and simply assigning this to internal pointers that's wrong.
you can do is use something like an strdup call as below
student->last = strdup(last);
student->first = strdup(first);
student->course = stddup(course);
or allocate space to last, first and course and copy the string
Your assumption is correct: You assigned pointers to stack objects to your list elements. So the content is likely to be overwritten on the course of further execution of the program, which gives you the weird characters in the output further down the road.
The correct way would be to allocate memory for the strings during createStudent which is done through malloc or calloc of minimum the length of the string. And you already have an example there in your function, so I'm a bit surprised that you stated you don't know how to do that. Another possibility is to call strdup for that purpose which basically does exactly the combination of allocation and string copy.
Oh and one more remark: Please make it a habit from the beginning of your career that you clean up after yourself. Meaning: Whatever you allocate, deallocate it after usage. In your case: If you have a createStudent function, create a destroyStudent function. If you have a linked list somewhere, free it before exitting the program. Picking that habit up early will save you from memory leaks in the future.

string.h and strncpy with pointers in C

I'm trying to create a user input created list that contains a structure with one int and two strings. But i seem unable to use correctly the strncopy from the string.h.
I'm supposed to use the order of the parameters like:
1. name of pointer
2. string to be copied
3. string length
The error i get says that 'name' and 'lastn' which are strings are not declared...so what am i missing here?
CODE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stats
{
int age;
char name[25];
char lastn[25];
struct stats *next;
};
void fill_structure(struct stats *s);
struct stats *create(void);
int main()
{
struct stats *first;
struct stats *current;
struct stats *new;
int x = 5;
//create first structure
first = create();
current = first;
for(x=0; x<5; x++)
{
if(x==0)
{
first = create();
current = first;
}
else
{
new = create();
current->next = new;
current = new;
}
fill_structure(current);
}
current->next = NULL;
current = first; //reset the list
while(current)
{
printf("Age %d, name %s and last name %s", current->age, strncpy(current->name, name, strlen(name)), strncpy(current->lastn, lastn, strlen(lastn)));
}
return(0);
}
//fill a structure
void fill_structure(struct stats *s)
{
printf("Insert Age: \n");
scanf("%d", &s->age);
printf("Insert Name: \n");
scanf("%s", &s->name);
printf("Insert Last Name: ");
scanf("%s", &s->lastn);
s->next = NULL;
}
//allocate storage for one new structure
struct stats *create(void)
{
struct stats *baby;
baby = (struct stats *)malloc(sizeof(struct stats));
if( baby == NULL)
{
puts("Memory error");
exit(1);
}
return(baby);
};
strncpy(current->name, name, strlen(name))
^ ^
You didn't declare any object named name. In your program the only name identifier is the name member of struct stats structure type.
The following line uses name and lastn, which are not defined.
printf("Age %d, name %s and last name %s", current->age, strncpy(current->name, name, strlen(name)), strncpy(current->lastn, lastn, strlen(lastn)));
It's not clear what you are trying to accomplish by the calls to strncpy here. It will be sufficient to use:
printf("Age %d, name %s and last name %s", current->age, current->name, current->lastn);
Also, while(current) will run for ever since you are not changing current in the loop. Use:
while(current)
{
printf("Age %d, name %s and last name %s", current->age, current->name, current->lastn);
current = current->next; // Need this
}
In fill_structure, instead of:
scanf("%s", &s->name);
scanf("%s", &s->lastn);
use
scanf("%s", s->name); // Drop the &
scanf("%s", s->lastn);

linked list insertion and sorting for C programming

Hello I am new to c so I had a few issues with my code. My code is supposed to display a menu which displays if you want to add, search, delete, or print all. This works however, my insertion part doesn't. When I select add and start typing the information I want the program crashes?
here is my code
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#pragma warning(disable: 4996)
//#define max 100
typedef enum { diploma, bachelor, master, doctor } education;
struct person { // a node to hold personal details
char name[30];
char email[30];
int phone;
education degree;
struct person* next;
} *head;
void branching(char c);
int insertion();
struct person *search(char *sname);
void deletion(char *sname);
void print_all();
char *x;
//Main Method
int main() { // print a menu for selection
char ch;
do {
printf("Enter your selection\n");
printf("\ti: insert a new entry\n");
printf("\td: delete an entry\n");
printf("\ts: search an entry\n");
printf("\tp: print all entries\n");
printf("\tq: quit \n");
ch = tolower(getchar());
branching(ch);
} while (ch != 113);
return 0;
}
void branching(char c) { // branch to different tasks
switch (c) {
case 'i':
insertion();
break;
case 's':
printf("Enter an item to search");
scanf("%s", x);
search(x);
break;
case 'd':
printf("Enter an item to delete");
scanf("%s", x);
deletion(x);
break;
case 'p':
print_all();
break;
case 'q':
break;
default:
printf("Invalid input\n");
}
}
//insert entry
int insertion(){
struct person *p;
p = (struct person*)malloc(sizeof(struct person));
if (p == 0){
printf("There are no more places to insert.\n"); return -1;
}
printf("Enter name, email, phone, and degree:\n");
scanf("%s", p->name);
scanf("%d", &p->phone);
scanf("%s", p->email);
scanf("%i", p->degree);
p->next = head;
head = p;
return 0;
}
//search method
struct person *search(char *sname){
struct person *p = head, *b = p;
printf("Please enter the name you wish to search:\n");
scanf("%c", sname);
while (p != 0)
if (strcmp(sname, p->name) == 0){
printf("Phone: %d\n", p->phone);
printf("Email: %s\n", p->email);
printf("Degree: %s\n", p->degree);
return b;
}
else{
b = p;
p = p->next;
}
printf("The name does not exist.\n");
return 0;
}
//delete entry
void deletion(char *sname){
struct person *t, *p;
p = head;
t = head;
while (t != NULL){
if (t->name == sname){
if (t == head){//case 1
head = t->next;
free(t);
return;
}
else{
p->next = t->next;
free(t);
return;
}
}
else{
p = t;
t = t->next;
}
}
return;
}
//print
void print_all(){
struct person *p;
p = head;
if (p = NULL){
printf("No entries found.");
}
else{
while (p != NULL){
printf("%s", p->name);
printf("%d", p->phone);
printf("%s", p->email);
printf("%s", p->degree);
p = p->next;
}
printf("\n");
}
}
The variable x needs to point to valid memory. When you make the declaration:
char * x;
The pointer is uninitialized and could point to anywhere in the computer's memory range.
This is why we recommend using std::string and the C++ streams, such as:
std::string x;
cin >> x;
// or
std::getline(cin, x);
Remember, if you dynamically allocate memory for C-Style strings, you have to deallocate the memory.
Also, you need to specify a maximum string length for your input. This is why scanf is an evil function. If you must use scanf, prefer it's other family members, such as fscanf(stdin) or use a format specifier with the maximum size specified.
When comparing the C-style string you will need to use strcmp. When copying the string, use strcpy. If you use std::string, you could use assignment operator and relational operators (more convenient and safe).

Segmentation fault in program using linked list

Code:
#include<stdio.h>
#include<malloc.h>
struct details{
char *name;
int no;
struct details *info;
};
//ADDING THE LINKED LIST
void add(struct details **info,int no,char * name){
struct details *temp=malloc(sizeof(struct details));
temp = *info;
if(temp == NULL){
temp = malloc(sizeof(struct details));
}
else{
if(temp->info == NULL){
temp->info = malloc(sizeof(struct details));
temp = temp->info;
}
}
temp->no = no;
temp->name = name;
}
//DISPLAYING THE LINKED LIST
void display(struct details *info){
while(info!=NULL){
printf("\nThe List is:\n","\n no: \tname:\n","%d","%s and link:%d",info->no,info->name,info->info);
info = info->info;
}
}
//MAIN PROGRAM
int main()
{
struct details* ptr;
char *name,ch;
int no;
int select_option;
ptr = NULL;
printf("\n ***MAIN MENU*** \n1.Add Element \n2.Delete Element \n3.Search Element \n4.Linked List Concatenation \n5.Invert Linked List \n6.Diplay Elements \n Please Enter your choice:(eg:1,2,3,4,5,6)\n");
scanf("%d",&select_option);
do{
switch(select_option){
case 1:
printf("Enter no to add:");
scanf("%d",&no);
printf("Enter name to add:");
scanf("%s",name);
add(&ptr,no,name);
break;
case 6:
display(ptr);
break;
default:
printf("INVALID CHOICE!");
break;
}
printf("Do u wish to continue?(y/n):");
scanf("%c",&ch);
}while(ch == 'y' || ch == 'y');
return 0;
}
I'm trying to write a simple program using a linked list to add and display data. But its throwing me a segmentation fault. I hope that I have initialized all the pointers with the memory. All help appreciated.
This:
temp->name = name;
does not copy name to temp->name but assigns temp->name to the same address as name, which is local to the function. You need to malloc() and strcpy():
temp->name = malloc(strlen(name) + 1);
strcpy(temp->name, name);
Remember to free(temp->name); when no longer required.
Additionally (as pointed out by Luchian), when reading from stdin:
char *name;
...
scanf("%s",name);
name has no memory allocated to. Declare it as an array but you need to protect against writing beyond the end of it:
char name[128];
...
scanf("%127s",name);
You haven't:
char *name;
///....
scanf("%s",name);
You never allocated memory for name.
You could do char name[50]; or whatever, but beware of overflows. Guard against them.
Both hmjd and Luchian Grigore answers are a prior problems, but also:
You don't initialize temp->info at any point after a malloc, so it is never NULL, but yet temp->info is an invalid address.
Either initialize it explicitly or use calloc, which initializes the allocated buffer, instead of malloc.
You forgot to allocate name
char *name

Memory error, access violation

I'm learning C on my own and as a exercise i have written a program but it does not work. The program is splitted into 3 parts. A header file, a main file for executing the program a file to define the functions. I'm not using all the functions yet but that shouldn't be the problem.
Here is my header file, nothing special in it.
#ifndef EMPLOYEE_H
#define EMPLOYEE_H
struct Employee
{
char first[21];
char last[21];
char title[21];
int salary;
};
struct Employee* createEmployee(char*, char*, char*, int); // Creates a struct Employee object on the heap.
char* getfirstname (struct Employee*);
char* getlastname (struct Employee*);
char* gettitle (struct Employee*);
int getsalary (struct Employee*);
void setfirstname (struct Employee*, char*);
void setlastname (struct Employee*, char*);
void settitle (struct Employee*, char*);
void setsalary (struct Employee*, int);
void printEmployee(struct Employee*);
#endif
In this file i define the functions and how they work:
#include "7.1.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Employee* createEmployee(char* first, char* last, char* title, int salary) // Creates a struct Employee object on the heap.
{
struct Employee* p = (struct Employee*) malloc(sizeof(struct Employee));
if (p != NULL)
{
strcpy(p->first, first);
strcpy(p->last, last);
strcpy(p->title, title);
p->salary = salary;
}
return p;
}
char* getfirstname (struct Employee* p)
{
if (p != NULL)
return p ? p->first : "";
}
char* getlastname (struct Employee* p)
{
if (p != NULL)
return p ? p->last : "";
}
char* gettitle (struct Employee* p)
{
if (p != NULL)
return p ? p->title : "";
}
int getsalary (struct Employee* p)
{
if (p != NULL)
return p ? p->salary : 0;
}
void setfirstname (struct Employee* p, char* first)
{
if (p != NULL)
strcpy(p->first, first);
}
void setlastname (struct Employee* p, char* last)
{
if (p != NULL)
strcpy(p->last, last);
}
void settitle (struct Employee* p, char* title)
{
if (p != NULL)
strcpy(p->title, title);
}
void setsalary (struct Employee* p, char* salary)
{
if (p != NULL)
p->salary = salary;
}
void printEmployee(struct Employee* p)
{
if (p != NULL)
{
printf("%s, %s, %s, %d",
p->first,
p->last,
p->salary,
p->salary
);
}
}
And the last file is used to executed the program/functions:
#include "7.1.h"
#include <stdio.h>
#include <stdlib.h>
int main ()
{
char decision;
struct Employee emp;
struct Employee* emps[3];
for ( int i = 0; i < 1; i ++)
{
printf("Please type in the emplooyes data.\nFirstname:");
scanf("%s", emp.first);
printf("Lastname:");
scanf("%s", emp.last);
printf("Title:");
scanf("%s", emp.title);
printf("Salary:");
scanf("%d", &emp.salary);
emps[i] = createEmployee(emp.first, emp.last, emp.title, emp.salary);
}
printf("Do you want to print out your information? (Y/N):");
scanf("%c", &decision);
if (decision == 'y' || decision == 'Y')
{
printEmployee(emps[1]);
}
}
I don't know what the problem is. I 'm always getting the following error message after typing in first, last, title and salary for the first time. The error is written in german. It means:
Unhandled exception at 0x102de42e (msvcr100d.dll) in 7.1.exe: 0xC0000005: Access violation when writing to 0xCCCCCCCC position.
I could fix the first problem with the hints given below. Now when i want to print out the employee data using the function:printEmployee(emps[1]);, I get the same kind of error with access violation.
For scanf for a number you need to specify the pointer to the number not the number itself. I.e.
scanf("%d", &emp.salary);
There may be other problems, but that's the first one I saw.
Your printf() arguments look off:
printf("%s, %s, %s, %d",
p->first,
p->last,
p->salary, // did you mean title here rather than salary?
p->salary
);
Also, you'll want to include new line character at the end of your format string:
printf("%s, %s, %s, %d\n", // note the \n
...
Your createEmployee() definition is also questionable:
p->salary, salary; // did you mean p->salary = salary?
don't know, if it's the only issue, but one trouble is :
scanf("%d", emp.salary);
Which is wrong (forgot address on salary with &)
better try : scanf("%d", &emp.salary);
++
This is how you're calling scanf():
scanf("%s", emp.salary);
This is how you're supposed to call scanf():
scanf("%s", &emp.salary); // note the address to the location you want
EDIT: As AlstairG points out, your strings (the char* members) are pointers and thus have the address already.

Resources