Adding records with pointers to arrays - c

I have to create a program which adds records to a simple phone book. The code is below, but it doesn't work - function ends and then it stucks on declaring struct record x and doesn't want to display my added record - the program breaks down. When I put this part of code on the end of the function (but instead of "struct record x = array[0];" I put "struct record x = (*array)[0]") it works - record is printed. So I guess the problem is something about pointers, but I'm struggling and I really couldn't find out what's wrong. I remember that few weeks ago I created a program which was very similar but it was adding a new record to an array of integers, with fixed values and it was working well, so maybe there's something with structures that I don't know about. Thanks for any help!
I know the program isn't done yet and I know that I didn't make any action for temp_array == NULL, it'll be done after I found out what's going on.
struct record {
char f_name[SIZE];
char name[SIZE];
long int phone;
};
int add_record(struct record** array, int n)
{
struct record* temp_array = malloc((n+1) * sizeof(struct record));
if (temp_array == NULL)
{
free(temp_array);
return -1;
}
int i;
for (i=0; i < n; i++)
{
temp_array[i] = (*array)[i];
}
struct record new_record;
printf("\nAplly data.");
printf("\nFirst name: "); /*fgets(new_record.f_name, SIZE, stdin);*/ scanf("%s", &new_record.f_name);
printf("Surname: "); /*fgets(new_record.name, SIZE, stdin);*/ scanf("%s", &new_record.name);
printf("Phone number: "); scanf("%d", &new_record.phone);
temp_array[n] = new_record;
free (*array);
*array = temp_array;
//struct record x = (*array)[0];
//puts(x.f_name); puts(x.name); printf("%d", x.phone);
return 0;
}
main()
{
struct record* array; int n = 0;
int choice;
printf("\n1. Add record\n2. Delete record\n3. Find record\n0. Exit\n\nChoose action: ");
scanf("%d", &choice);
switch(choice) {
case 0: printf("\nKsiazka zostala zamknieta.\n"); return;
case 1: add_record(&array, n); n++; break;
case 2: return;
case 3: return;
default: printf("Wrong choice.\n\n"); return;
}
struct record x = array[0];
puts(x.f_name); puts(x.name); printf("%d", x.phone);
}

struct record* array=NULL;, and use %ld for long int – BLUEPIXY

Related

Modifying data in a Linked List in C?

When I modify the linked list (based on the ID), it modifies the node successfully but deletes the rest of the list. The whole list stays only if I modify the most recent node that I've added to the list.
I know that the problem is at the end where it says:
phead=i;
return phead;
But I don't know how to fix it as I haven't found anything to help me, even though I'm sure it is simple to know why it is wrong.
struct ItemNode *modify1Item(struct ItemNode *phead){
int modID;
int lfound=0;
int lID;
char lDesc[30];
char lName[30];
double lUPrice;
int lOnHand;
struct ItemNode *i=phead;
printf("Enter the ID of the item that you want to modify\n");
scanf("%d", &modID);
while(i != NULL){
if(i->ID == modID){
break;
}
i= i->next;
}
if(i==NULL){
printf("An item with that ID wasn't found.\n");
return 0;
}
else{
printf("Enter new Name\n");
scanf("%s", lName);
strcpy(i->name, lName);
printf("Enter new Description\n");
scanf("%s", lDesc);
strcpy(i->desc, lDesc);
printf("Enter new Unit Price $\n");
scanf("%lf", &lUPrice);
i->uPrice = lUPrice;
printf("Enter new Number of Items On Hand\n");
scanf("%d", &lOnHand);
i->onHand = lOnHand;
}
phead=i;
return phead;
}
When I return it, i say head=modify1Item(phead);
I tested your code everything worked as expected. Without seeing your code, I can't comment much. But I think, for your code, the only time everything would get delete is if you assign the return value incorrectly. So this below is probably something close to your code. For the test code below, unless you modify it, the IDs are 0, 1, and 2. Oh and the reason why I commented only work for 0 to 9 is because I don't want to make up the entire char string so I used i ^ 48. Of which, 0 - 9 ^ 48 would turn into the correspondent ASCII code of 0 - 9. If you go beyond that, you may get weird result for that two string that all.
I just noticed that you use NULL in your search. Thus, I updated the code so the "next" of last index will be NULL otherwise if your code found nothing, it will run forever.
#include <stdio.h>
#include <string.h>
typedef struct ItemNode {
int ID;
int uPrice;
int onHand;
char name[30];
char desc[30];
struct ItemNode * next;
} ItemNode ;
struct ItemNode * modify1Item(struct ItemNode * phead){
int modID;
int lfound=0;
int lID;
char lDesc[30];
char lName[30];
double lUPrice;
int lOnHand;
struct ItemNode *i = phead;
printf("Enter the ID of the item that you want to modify\n");
scanf("%d", &modID);
while(i != NULL){
if(i->ID == modID){
break;
}
i = i->next;
}
if(i==NULL){
printf("An item with that ID wasn't found.\n");
return 0;
} else {
printf("Enter new Name\n");
scanf("%s", lName);
strcpy(i->name, lName);
printf("Enter new Description\n");
scanf("%s", lDesc);
strcpy(i->desc, lDesc);
printf("Enter new Unit Price $\n");
scanf("%lf", &lUPrice);
i->uPrice = lUPrice;
printf("Enter new Number of Items On Hand\n");
scanf("%d", &lOnHand);
i->onHand = lOnHand;
}
phead=i;
return phead;
}
int main(){
// only work for 0 - 9.
int index = 3;
ItemNode iArr[index];
for ( int i = 0; i < index; i++ ){
iArr[i].ID = i;
iArr[i].uPrice = i + i;
iArr[i].onHand = i * i;
iArr[i].name[0] = i ^ 48;
iArr[i].desc[0] = i ^ 48;
// If last index link back to first index.
// Updated: but for you usage case
// because of your search function
// last index should be NULL otherwise your
// search will run forever
if ( i < index - 1 ) iArr[i].next = &iArr[i + 1];
else iArr[i].next = NULL; // if change search method with unique ID then you can use -> &iArr[0];
}
// Mod 0
ItemNode * test = modify1Item(iArr);
printf("0 name: %s\n\n",iArr[0].name );
// Mod 1
ItemNode * test1 = modify1Item(iArr);
printf("1 name: %s\n\n",iArr[1].name );
// Mod 2
ItemNode * test2 = modify1Item(iArr);
printf("2 name: %s\n\n",iArr[2].name );
// Check if 0 is still there.
printf("0 name: %s\n\n",iArr[0].name );
return 0;
}

C programming : Grouping multiple strings and searching for it using an Unique key

Let's say for example you are entering the personal information of a student and you create a unique ID number for each student. What I'm having problems with is grouping those strings, and storing them together, so that it can be accessed through the ID.
I tried using memory allocation, however, it did not work out.
I'm quite new to C, so I'm not exactly sure on what to do.
Here is what I used :
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct {
int LogID;
char firstname[20];
char lastname[20];
int mark;
char *subjects[100];
} student;
int reg(void);
int main(void) {
reg();
return 0;
}
//Registration function
int reg(void) {
int choice,shift,found,compare, nosub, y, sub, subcount;
char studentname[20];
FILE *fp;
FILE *fp2;
printf("Enter Student Details:\n\nStudent ID: ");
scanf("%d",&student.LogID);
printf("Name: ");
scanf("%s",student.firstname);
printf("Surname: ");
scanf("%s",student.lastname);
printf("How many subjects does the student take? ");
scanf("%d", &nosub);
//Opens a text file and prints the student's ID and firstname
fp2=fopen("subjects.txt","a+");
fprintf(fp2, "\n\n%d\t%s", student.LogID, student.firstname);
int i = 1;
size_t malloc_size = 100; //Allocating memory size to store subjects student is taking
for(i = 0; i < nosub; i++) {
student.subjects[i] = malloc(malloc_size * sizeof(char));
printf("Please enter the subject :\n(1)Mathematics\n(2)English\n(3) Social Studies\n(4)Science\n");
scanf("%d", &sub);
switch (sub) {
case (1) :
printf("Mathematics\n");
break;
case (2) :
printf("English\n");
break;
case (3) :
printf("Social Studies\n");
break;
case (4) :
printf("Science\n");
break;
}
}
for(i = 0; i < nosub; i++) { //Prints subjects to file, but it doesn't work...
fprintf(fp2,"%s\n", student.subjects[i]);
}
fclose(fp2);
free(student.subjects[i]);
student.subjects[i] = NULL;
fp=fopen("studentfile.txt","a+");
//Prints certain student Information into another file...
fprintf(fp,"\n%d\t%s\t%s\t",student.LogID,student.firstname,
student.lastname);
fclose(fp);
printf("Registration has been successful\n");
getchar();
return 0;
}
There were a number of issues I noticed and I'll address some of them, starting with the struct which I recommend defining like this:
struct studentpack {
int LogID;
char firstname[20];
char lastname[20];
int mark;
char *subjects[100];
};
And under your main function, you can define the student entry for filling.
struct studentpack student;
which will be used over and over again in your code, as you did in your example, for filling from the user input.
In the switch you really don't need any parenthesis around the case numbers.
In addition to the printf statement in each case, try something like this:
case 1:
printf("%s\n", "Mathematics");
sprintf(student.subjects + i, "%s", "Mathematics");
break;
which will fill the subjects area that you memory allocated just prior.
Finally, for grouping together the ID's I would suggest starting with something like this:
#define MAXGROUP 1000
struct studentpack *group = calloc(MAXGROUP, sizeof(struct studentpack));
int studentno = 0;
And then after you print your subjects to the file (test that it is working first due to the sprintf change) you would assign to the group like this:
if (studentno < MAXGROUP) {
memcpy(group+studentno, &student, sizeof(struct studentpack));
studentno++;
}
The above will store away the student. Next you will probably want to iterate through the group variable, accessing group[0].LogID, group[1].LogID, etc. (all the way up to a maximum of 1000) just to confirm that all your data is there in memory.
For example you could write a function that steps through looking for a particular LogID and then calls a show or display function containing printf statements to see all the values on screen.
you need an array of students
struct student{
int LogID;
char firstname[20];
char lastname[20];
int mark;
char *subjects[100];
};
struct student students[100];
you now have space for 100 students. They are students[0], students[1],...students[99]
Now you can do
int studno = 0;
While(something)
{
printf("\Enter Student Details:\n\nStudent ID: ");
scanf("%d",&(students[studno].LogID));
....
studno++;
}

Dynamically allocated memory in structure in c

I'm trying to create two lists, pros and cons and then print them.
But I can't figure out what am I doing wrong.
I tried to debug the program with gdb online and I found out that the error is in function fgets().
#include <stdio.h>
#include <string.h>
typedef struct list{
char ** reason;
} list;
void printMenu();
void printList(list * myList, int len1);
int main(void)
{
int keepGoing = 0;
int choice = 0;
int i = 0;
int j = 0;
list * pros;
list * cons;
while (!keepGoing){
printMenu();
scanf("%d", &choice);
pros = (list*)malloc(sizeof(list));
cons = (list*)malloc(sizeof(list));
switch (choice){
case 1:
i++;
printf("Enter a reason to add to list PRO: ");
pros = (list*)realloc(pros, i*sizeof(list));
fgets(pros->reason[i], 50, stdin);
pros->reason[strcspn(pros->reason[i], "\n")] = 0;
break;
case 2:
j++;
cons = (list*)realloc(cons->reason, j*sizeof(list));
printf("Enter a reason to add to list CON: ");
fgets(cons->reason[j], 50, stdin);
cons->reason[strcspn(cons->reason[j], "\n")] = 0;
break;
case 3:
printf("PROS:\n");
printList(pros, i);
printf("CONS:\n");
printList(cons, j);
break;
case 4:
keepGoing = 1;
break;
default:
printf("Invalid value.");
keepGoing = 1;
}
}
free(pros);
free(cons);
getchar();
return 0;
}
void printList(list * reasons, int len1){
int i = 0;
for (i = 0; i < len1; i++){
printf("%s\n", reasons->reason[i]);
}
}
void printMenu(){
printf("Choose option:\n");
printf("1 - Add PRO reason\n");
printf("2 - Add CON reason\n");
printf("3 - Print reasons\n");
printf("4 - Exit\n");
}
There is no need to allocate these dynamically: list * pros; list * cons;. Code like pros = (list*)realloc(pros, i*sizeof(list)); doesn't make any sense.
Instead, declare them as plain variables. list pros.
What you instead need to allocate dynamically is the member pros.reason. You need to allocate an array of pointers that it points to, and then you need to allocate the individual arrays.
You have a problem in
fgets(pros->reason[i], 50, stdin);
as the memory you want to use is not valid. pros->reason does not point to a valid memory, so you cannot dereference it, this causes undefined behavior.
Before you can index-into pros->reason, you need to make pros->reason point to a valid memory location.
After that, you need to make pros->reason[i]s also to point to valid memory if you want them to be used as the destination of fgets().
Apart from this issue, you have another issue which makes this code nonsense, that is calling malloc() on every iteration of the loop. You need to call malloc() only once, to get a pointer (to memory) allocated by memory allocator function and then, use realloc() inside the loop to adjust that to the required memory.
There are many issues. Previous comments and answers do still apply.
Here is a clean solution.
The list structure is now self contained, no need to track the number of strings in separate variables
added selfcontained AddString function
no more unnecessary mallocs
all allocated memory is freed correctly
some logic errors removed (inverted logic of keepGoing)
There is still room for improvement. Especially there is no error checking for the memory allocation functions.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct list {
int size; // number of strings
int chunksize; // current of chunk
char ** reason;
} list;
void printMenu();
void printList(list * reasons);
void freeList(list * l);
void AddString(list *l, const char *string);
int main(void)
{
int keepGoing = 1;
int choice = 0;
list pros = { 0 }; // = {0} initializes all fields to 0
list cons = { 0 };
while (keepGoing) {
printMenu();
scanf("%d", &choice);
char input[50];
fgets(input, sizeof(input), stdin); // absorb \n from scanf
switch (choice) {
case 1:
printf("Enter a reason to add to list PRO: ");
fgets(input, sizeof(input), stdin);
AddString(&pros, input); // Add string to pros
break;
case 2:
printf("Enter a reason to add to list CONS: ");
fgets(input, sizeof(input), stdin);
AddString(&cons, input); // Add string to cons
break;
case 3:
printf("PROS:\n");
printList(&pros);
printf("CONS:\n");
printList(&cons);
break;
case 4:
keepGoing = 0;
break;
default:
printf("Invalid value.");
keepGoing = 1;
}
}
freeList(&pros);
freeList(&cons);
getchar();
return 0;
}
#define CHUNKSIZE 10
void AddString(list *l, const char *string)
{
if (l->size == l->chunksize)
{
// resize the reason pointer every CHUNKSIZE entries
l->chunksize = (l->chunksize + CHUNKSIZE);
// Initially l->reason is NULL and it's OK to realloc a NULL pointer
l->reason = realloc(l->reason, sizeof(char**) * l->chunksize);
}
// allocate memory for string (+1 for NUL terminator)
l->reason[l->size] = malloc(strlen(string) + 1);
// copy the string to newly allocated memory
strcpy(l->reason[l->size], string);
// increase number of strings
l->size++;
}
void freeList(list * l) {
for (int i = 0; i < l->size; i++) {
// free string
free(l->reason[i]);
}
// free the list of pointers
free(l->reason);
}
void printList(list * l) {
for (int i = 0; i < l->size; i++) {
printf("%s\n", l->reason[i]);
}
}
void printMenu() {
printf("Choose option:\n");
printf("1 - Add PRO reason\n");
printf("2 - Add CON reason\n");
printf("3 - Print reasons\n");
printf("4 - Exit\n");
}

Searching through a linked list.

So i've been trying to understand the difference between a regularly defined structure without using malloc linked list that does utilize malloc.
The issue that i'm having right now is trying to search through the structure (pi) to find each part number that has a cost greater than what was entered into the search. this is my entire program so far. I've added comments for each section.
I'm simply not sure how i am suppose to search through each structure to compare its price to the search price.
#include <stdio.h>
#include <stdlib.h>
struct Item {
int quantity;
float cost;
char partNum[10];
struct Item *next;
};
void printItem(struct Item* pi);
void enterItem(struct Item* pi);
char search [100];
void main(int argc, char* argv[])
{
struct Item *pi;
struct Item *head;
int done = 0;
int i,j;
char choice;
// ENTERING ITEM INTO THE STRUCTURE
head = NULL;
while (!done) {
printf("Enter another item? (y/n)");
choice = getchar();
if (choice == 'y' || choice == 'Y') {
pi = (struct Item *)malloc(sizeof(struct Item));
enterItem(pi);
pi->next = head;
head = pi;
} else {
done = 1;
}
}
// SEARCHING FOR ITEM BY PRICE
printf("Enter a price to find all items more expensive, or type 'exit':");
while (strcmp(search, "exit") !=0) {
gets(search);
for (j = 0; j<i ; i++) {
if (strcmp(pi[j].cost, search) ==0) {
printItem(pi);
pi = pi->next;
}
}
}
}
getchar();
getchar();
}
// FUNCTION FOR PRINTING STRUCTURE ITEM
void printItem(struct Item* pi) {
printf("Quantity: %d\n", pi->quantity);
printf("Cost: $%.2f\n", pi->cost);
printf("Part # %s\n", pi->partNum);
printf("\n\n");
}
// FUNCITON FOR ENTERING IN NEW ITEM
void enterItem(struct Item* pi) {
printf("Quantity? ");
scanf("%d", &pi->quantity);
printf("Cost? ");
scanf("%f", &pi->cost);
getchar(); //need to clear out the carriage return from typeing in the cost
printf("Part Number? ");
gets(pi->partNum);
}
What you were doing wrong is comparing string(search variable) with a float(cost variable) using strcmp. This won't give you the desired output.
Instead, lets use -1 to indicate the exit, since parsing string and converting it to float is off-topic. Start iterating from head up to finding NULL, and compare the prices of the each item.
float price;
struct Item *it = head;
printf("Enter a price to find all items more expensive, or type '-1' to exit:");
scanf("%f", price);
// check price for the 'exit' -- compare with -1
while (it != NULL) {
if (it->cost > price)
printItem(pi);
it = it->next;
}

How do you assign values entered in a structure to an array?

I'm having a little trouble doing this. I'm creating a program that will store individuals information by ID number using a structure. I need to store then in an array then search through it with a for loop (easy). Whenever I try to compile I get an error saying request for member "blah blah" in something not a structure or union.
I'm getting this error for the final printf statement.
#include <stdio.h>
#include <stdlib.h>
struct infoStruct
{
int studentID;
int year;
int month;
int day;
int phone;
int end;
};
int main (void)
{
int students = 0;
struct infoStruct *info = NULL;
while (info.end != -1) {
students = students + 1;
printf("Enter student information (ID, day, month, year, phone)\n");
printf("Enter -1 following the phone number to end the process to continue enter 0\n");
info = malloc(sizeof(struct infoStruct) * students);
scanf("%d %d %d %d %d %d", &info.studentID, &info.day, &info.month, &info.year, &info.phone, &info.end);
}
printf("You entered %d student(s)\n", students);
printf("Enter Student ID\n");
scanf("%d", info.studentID);
}
First, your array should be of type infoStruct.
You should know the value of students. Then you can do something like:
for (int i=0;i<students;++i)
{
scanf(%d %d"[...],&infoArray[i].studentID, &infoArray[i].year[...]);
}
"info" is a pointer. So to access its values you should unreference it. As you are using array of struct you can do it in the following way:
scanf("%d %d %d %d %d %d", &info[some_counter].studentID, &info[some_counter].day, &info[some_counter].month, &info[some_counter].year, &info[come_counter].phone, &info[come_counter].end);
Also it is better to use realloc() call to change size of array of structs and fix in some way end of loop condition. Now it makes a crash because info is NULL and right before start you are trying to dereference this NULL pointer.
Loop with realloc() may look like following code:
while (true) {
printf("Enter student information (ID, day, month, year, phone)\n");
printf("To finish enter word \"end\"\n");
struct infoStruct *new_info = realloc(info, (students+1)*sizeof(struct infoStruct));
if (new_info == NULL) {
printf("Out of memory! errno = %s\n", strerror(errno));
break;
} else {
info = new_info;
}
result = scanf("%d %d %d %d %d %d",
&info[students].studentID,
&info[students].day,
&info[students].month,
&info[students].year,
&info[students].phone,
&info[students].end
);
if (result != 6) {
students--;
info = realloc(info, sizeof(struct infoStruct) * students);
break;
}
students++;
}
This:
int students = 0;
...
int infoArray [students];
...
while()
{
students = students + 1;
...
}
Will not work. You have to declare the size of your array a priori and it can't change during run-time without explicitly reallocating it.
What you can do is:
printf("What's the number of students you want?\n");
scanf("%d", &students);
...
int infoArray [students];
...
while(i++ < students)
{
// collect the data...
...
}
Since you can't change the size of the array dynamically in C without explicitly reallocating it, you will have to go for a linked list solution if you want a dynamic solution.
infoArray is declared a int. It does not provide structure elements like
infoArray.studentID. That causes the compiler to complain ... something not a structure or union.
infoArray [students]; with int students = 0; is questionable too.
You'd get (rewritten to suit the need. However, with some open questions):
#include <stdio.h>
#include <stdlib.h>
#define MAX_STUDENTS 200
typedef struct {
int studentID;
int year;
int month;
int day;
int phone;
int end;
} info_TYPE;
int main (void)
{
info_TYPE infoArray [MAX_STUDENTS];
int students = 0;
while (infoArray[students].end != -1) {
printf("Enter student information (ID, day, month, year, phone)\n");
printf("Enter -1 following the phone number to end the process to continue enter 0\n");
scanf("%d %d %d %d %d %d", &infoArray[students].studentID, &infoArray[students].day, &infoArray[students].month, &infoArray[students].year, &infoArray[students].phone, &infoArray[students].end);
students = students + 1;
if (students >= MAX_STUDENTS) break;
}
if (infoArray[students - 1].end = -1) printf("You entered %d student(s)\n", students);
printf("Enter Student ID", infoArray[students - 1].studentID);
// no idea what this line was for, presumably another previous attempt.
scanf("%d", infoArray[students - 1].studentID);
// getting tired to follow the speed at which the question is modified, presumably last edit here!
}
The compiler is complaining because
printf("Enter Student ID", infoArray.studentID);
treats infoArray.studentID as a structure member, which it is not.

Resources