How to get struct from a file in C - c

I am new to programming and would like some help in for File in C.
This is my code
#include <stdio.h>
#include <string.h>
void read_file();
void write_fil();
void add();
void display();
void search();
#define NAME_CHRS 30
struct employee_rec
{ char name[NAME_CHRS];
int dependents;
float pay_rate;
};
struct employee_rec employee;
struct employee_rec emp_array[];
FILE *employ;
int count=-1;
void read_file(void)
{
int idx;
employ = fopen("EMPLOYEE.DAT", "a+");//i add
//for (idx=0; idx <= count; idx++)
fread(&emp_array[idx], sizeof emp_array[idx], 1, employ);
fclose(employ);
}
void write_file()
{
int x;
employ = fopen("EMPLOYEE.DAT", "a+");
for (x=0; x <= count; x++)
fwrite(&emp_array[x], sizeof emp_array[x], 1, employ);
fclose(employ);
}
void add()
{
count+=1;
printf("Enter name: ");
scanf("%s", emp_array[count].name);
printf("Pay rate, other dependents: ");
scanf("%f %i", &emp_array[count].pay_rate, &emp_array[count].dependents);
}
void display()
{
int idx;
read_file();
printf("Name\t\tPay Rate\tDependents\n");
printf("----\t\t--------\t----------\n");
for (idx=0; idx <= count; idx++)
{
printf("%-10s\t%-8g\t%-8d\n", emp_array[idx].name, emp_array[idx].pay_rate, emp_array[idx].dependents);
}
}
void search()
{
char target[20];
int idx, found=0;
printf("Enter a name to search: ");
scanf("%s", target);
for (idx=0; idx <= count; idx++){
if(strcmp(emp_array[idx].name, target) == 0)
{
found = 1;
break;
}
}
if(found == 1)
{
printf("Name: %s\n", emp_array[idx].name);
printf("Pay rate: %g\n", emp_array[idx].pay_rate);
printf("Dependents: %d\n", emp_array[idx].dependents);
}
else
printf("Not found!\n");
}
int main(void)
{
int i;
//for (i=0; i < 3; i++)
// add();
// write_file();
display();
search();
return 0;
}
The original program would ask the user to key in data and then display it for the user.
So when another user runs the program and has the file it doesnt need to add more data but just read from the file
I have commented the for loop, display and search in my main because i just want to retrieve the data from my file.
Im not sure what to do with
fread(&emp_array[idx], sizeof emp_array[idx], 1, employ);
fclose(employ);
Since right now im using the counter from the insert to get the size, it will say size is 0 as the current run did not enter the data into the file (file already has data).
Is there any other way I can get all my data from the file without inserting it in the same run?
EDIT: So as some of the comments have mentioned the size of emp_arry is empty. I would like to get the size from a file. Since the file as a array inside which i want to transfer the data to emp_array.

One simple solution is to design a file header which includes the number of data in this file. Then, you can first read file header to get the number and then dynamically allocate memory to read data from file.

Related

Segmentation fault: zsh: segmentation fault

I get a segfault when I add (int filter) in the struct. Is it possible to fix?
Error message: zsh: segmentation fault
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
typedef struct Student {
char name[30];
char surname[30];
int course; // year of study
double average; // average grade
int load; // number of courses
char courses[10][30]; // course names
int grades[10]; // course grades
char languages[100]; // spoken languages
int negative;
// int filter;
} Student;
int main(int argc, char *argv[]) {
FILE *db = NULL;
// open database file for reading, provide a parameter or use default "db.bin"
if (argc > 1)
db = fopen(argv[1], "rb");
else
db = fopen("db.bin", "rb");
if (db){
Student students[1000]; // all the data goes here
int size = 0; // how many students in database
// reading data from file
fread(&size, sizeof(int), 1, db);
for (int i = 0; i < size; i++){
fread(&students[i], sizeof(Student), 1, db);
}
printf("%d records loaded succesfully\n", size);
// MODIFY CODE BELOW
int counterDemo = 0; // for counting students
for (int i = 0; i < size; ++i){ // process all the student records in database
Student s = students[i]; // store data for each student in s
s.negative = 0;
// Checking if student has Philosophy and passed Philosophy exam
for(int j = 0; j < s.load; ++j)
{
if(!strcmp(s.courses[j], "Philosophy"))
{
s.negative++;
}
}
bool philosophy_exam = false;
if(s.negative != 0) // If student has Philosophy and passed Philosophy exam
{
philosophy_exam = true;
}
if(philosophy_exam){ // *** first filter, conditions on the student
int anotherDemo = 0; // for counting courses/grades
printf("%s %s %d %.2f %d ", s.name, s.surname, s.course, s.average, s.load); // print student data
for (int i = 0; i < s.load; ++i){ // process each course taken by the student
if(1){ // *** second filter, conditions on the course/grade
++anotherDemo; // counting courses
printf("%s %d ", s.courses[i], s.grades[i]);
}
}
printf("%s\n", s.languages);
if (anotherDemo == s.load) // *** third filter, various other conditions
++counterDemo; // counting studfents
}
}
printf("Filter applied, %d students found\n", counterDemo); // how many passed the filters
fclose(db);
} else {
printf("File db.bin not found, check current folder\n");
}
return 0;
}
I commented the problematic variable out.
Also I run my code on terminal, like always. I am using (clang "file" -o main) could this be the problem? I have tried to run this code in different apps, but it doesn't help.

Problem with reload data function and save data function

I'm learning about disjoint dynamic memory, so I'm trying to make my own program. I need someone to help me see my problems and show me how to fix them.
I'm almost done with my program, but still have some problems in my program.
My problem:
my saveData() function and reload() function do not work correctly.
I'm not sure whether the saveData() function does get all the data I need
my reload() function just output it has brought back data from the bin file (in saveData() function) and then exit program with some weird code (ex: 8500241654)
Without the above problem, my program works well. Please check the 3 problems in my program in .h file and .c file
C Program Description:
"You will write a program that will store the information about automobiles. The information is about make, mode, yearBuilt, and cost (use struct). The user will choose from menu what they want to do (add auto, display auto with orders of cost or make, use switch).
When the program begins, if there was a previous data file of automobile information it will be loaded automatically. The program will begin where the user last left off. If there is no previous data file, then the program will ask the user how many automobiles record will be needed and the program will start fresh.
When the program ends, all data will be saved to a bin file. All memory will be released from the heap. "
P/s: thank you so much, and appreciate your help.
<Here is my .h file>
// FUNCTION PROTOTYPES
typedef struct {
char make[50]; // ex: Ford, Honda, Toyota
char model[50]; // ex: Corolla, Camry
int yearBuilt; // ex: 2001, 2022
int cost; // ex: 20500, 8999, 15000
} AUTOMOBILE; // 108 bytes
void addAuto(AUTOMOBILE* a[], int* eSize, int size);
int compareChars(const void* a, const void* b);
void displayAuto(AUTOMOBILE* autos[], int eSize);
void displayMenu();
void freeMemory(AUTOMOBILE* autos[], int size);
int getInt(char m[]);
int getCh(char m[]);
void quitProgram(int* temp);
AUTOMOBILE** reload(AUTOMOBILE* a[], int* eSize, int* size);
void saveData(AUTOMOBILE *a[], int eSize, int size);
void sortByCost(AUTOMOBILE* autos[], int eSize);
void sortByMake(AUTOMOBILE* autos[], int eSize);
// FUNCTIONS
void addAuto (AUTOMOBILE *a[], int* eSize, int size) {
char again = 'N';
char autoMake[50];
char autoModel[50];
do {
if (*eSize == size) {
printf("No room to add more automobile...it is full!\n");
system("pause");
return;
}
printf("\nAdding a new automobile to the array of items\n");
// add make
printf("What is the automobile's make (uppercase first letter, ex: Honda)? ");
scanf("%s", a[*eSize]->make);
// add model
printf("What is the automobile's model (uppercase first letter, ex: Camry)? ");
scanf("%s", a[*eSize]->model);
// add year built
a[*eSize]->yearBuilt = getInt("When was the automobile built (ex: 2022)? ");
// add cost
a[*eSize]->cost = getInt("How much does the automobile cost (ex: 45500)? ");
*eSize += 1;
printf("\nWould you like to add another item? [Y/N]: ");
scanf(" %c", &again);
} while (toupper(again) == 'Y');
} // end addAuto
int compareChars(const void* a, const void* b) {
const char* arg1 = *(const char**) a;
const char* arg2 = *(const char**) b;
return strcmp(arg1, arg2);
} // end compareChars
void displayAuto(AUTOMOBILE *autos[], int eSize) {
char option;
printf("\nChoose your desired order");
printf("\n[C]ost low to high");
printf("\n[M]ake ascending order");
option = getCh("\nEnter option: ");
if (option == 'C' || option == 'c')
sortByCost(autos, eSize);
else if (option == 'M' || option == 'm')
sortByMake(autos, eSize);
} // end displayAuto
void displayMenu() {
printf("\n[A]dd one automobile");
printf("\n[D]isplay all automobiles by");
printf("\n\t[C]ost low to high");
printf("\n\t[M]ake ascending order"); // ascending order: A-Z
printf("\n[Q]uit program\n");
} // end displayMenu
void freeMemory(AUTOMOBILE* autos[], int size) {
for (int i = 0; i < size; i++) {
free(autos[i]);
}
free(autos);
} // end freeMemory
int getCh(char m[]) {
char result;
char badValue = 'F';
// loop until get integer value
do {
badValue = 'F';
printf("%s", m);
scanf(" %c", &result);
// if "result" isn't an alphabet, do the loop again
if (isalpha(result) == 0) {
printf("\nYou must enter a valid character!\n");
badValue = 'T';
} // end If
} while (badValue == 'T');
return result;
} // end getCh
int getInt(char m[]) {
int result = 0;
char badValue = 'F';
// loop until get integer value
do {
badValue = 'F';
printf("%s", m);
if (scanf("%i", &result) != 1) {
printf("\nYou must enter a valid real numeric value!\n");
badValue = 'T';
} // end If
} while (badValue == 'T');
return result;
} // end getInt
void quitProgram(int *temp) {
printf("\nThank you for using program!\n");
*temp = 1;
} // end quitProgram
AUTOMOBILE** reload(AUTOMOBILE* a[], int* eSize, int* size) {
*eSize = 0;
FILE* fp = fopen("binaryDocument.bin", "rb");
if (fp == NULL) {
printf("\nNo information has been reload!\n");
system("pause");
return a;
} // end if
printf("\nI have brought back the previous saved data into the array!\n");
system("pause");
// get the size
fread(size, sizeof(int), 1, fp);
// memory allocation for [size] pointers, [size] * 4 bytes of space
// use the size to allocate the space for the pointer array
a = calloc(*size, sizeof(AUTOMOBILE*));
if (a == NULL) {
printf("Allocation of memory failed...\n");
exit(-1);
}
// go through each one of them, and allocate 108 bytes each and allow these pointers to refer to it
for (int i = 0; i < size; i++) {
a[i] = calloc(1, sizeof(AUTOMOBILE));
if (a[i] == NULL) {
printf("Allocation of memory at autos[%i] failed...\n", i);
exit(-1);
}
}
// get the eSize and use the eSize to reload the array
fread(eSize, sizeof(int), 1, fp);
fread(a, sizeof(AUTOMOBILE*), *eSize, fp);
fclose(fp);
return a;
} // end reload
void saveData(AUTOMOBILE *a[], int eSize, int size) { // PROBLEM HERE
FILE* fp = fopen("binaryDocument.bin", "wb");
if (fp == NULL) {
printf("\nCould not save the information to a binary file\n");
system("pause");
return;
} // end if
fwrite(&size, sizeof(int), 1, fp);
fwrite(&eSize, sizeof(int), 1, fp);
fwrite(a, sizeof(AUTOMOBILE*), eSize, fp);
fclose(fp);
} // end saveData
void sortByCost(AUTOMOBILE *autos[], int eSize) {
int temp = 0;
int autoCost[1000];
for (int i = 0; i < eSize; i++) {
autoCost[i] = autos[i]->cost;
}
for (int i = 0; i < eSize; ++i) {
for (int j = i + 1; j < eSize; ++j) {
if (autoCost[i] > autoCost[j]) {
temp = autoCost[i];
autoCost[i] = autoCost[j];
autoCost[j] = temp;
}
}
}
printf("\nAutomobiles are displayed from low to high in term of cost: \n");
for (int l = 0; l < eSize; l++) {
for (int k = 0; k < eSize; k++) {
if(autoCost[l] == autos[k]->cost)
printf("%i\t%s\t%s\t%i\n", autoCost[l], autos[k]->make, autos[k]->model, autos[k]->yearBuilt);
}
}
} // end sortByCost
void sortByMake(AUTOMOBILE *autos[], int eSize) {
qsort(autos, eSize, sizeof(AUTOMOBILE*), compareChars);
printf("\nAutomobiles are displayed A-Z: \n");
for (int i = 0; i < eSize; i++) {
printf("%s\t%s\t%i\t%i\n", autos[i]->make, autos[i]->model, autos[i]->yearBuilt, autos[i]->cost);
}
} // end sortByMake
<Here is my .c file>
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "DJDMHeader.h"
//****************************************************
// MAIN FUNCTION
int main() {
int size = 0;
int eSize = 0;
AUTOMOBILE** autos = NULL; // create the variable to make the array of automobile pointers
int i, temp = 0;
char choice;
// reload data
autos = reload(autos, &eSize, &size);
// case: nothing to reload, start fresh
if (size == 0) {
// get integer value for variable size
size = getInt("How many automobiles will you have at the most: ");
// memory allocation for [size] pointers, [size] * 4 bytes of space
autos = calloc(size, sizeof(AUTOMOBILE*));
if (autos == NULL) {
printf("Allocation of memory failed...\n");
exit(-1);
}
// go through each one of them, and allocate 108 bytes each and allow these pointers to refer to it
for (i = 0; i < size; i++) {
autos[i] = calloc(1, sizeof(AUTOMOBILE));
if (autos[i] == NULL) {
printf("Allocation of memory at autos[%i] failed...\n", i);
exit(-1);
}
}
}
while (temp == 0) {
displayMenu();
choice = getCh("What is your choice?: ");
// switch
switch (choice) {
case 'a':
case 'A':
addAuto(autos, &eSize, size);
break;
case 'd':
case 'D':
displayAuto(autos, eSize);
break;
case 'q':
case 'Q':
quitProgram(&temp);
break;
default:
printf("\nPlease choose the existed choices!\n");
}
}
// Save data
saveData(autos, eSize, size);
// Free memory
freeMemory(autos, size);
return 0;
}
If anything about my program or my question make you unhappy (or something like that), please tell me, I will edit again. So much thanks.
You either operate on an array:
#include <stdio.h>
typedef struct {
char make[50]; // ex: Ford, Honda, Toyota
char model[50]; // ex: Corolla, Camry
int yearBuilt; // ex: 2001, 2022
int cost; // ex: 20500, 8999, 15000
} AUTOMOBILE;
// array
void saveData(AUTOMOBILE *a, int eSize, int size) {
FILE *fp = fopen("binaryDocument.bin", "wb");
if (!fp) {
printf("\nCould not save the information to a binary file\n");
return;
}
fwrite(&size, sizeof(int), 1, fp);
fwrite(&eSize, sizeof(int), 1, fp);
fwrite(a, sizeof(*a), eSize, fp);
fclose(fp);
}
int main() {
AUTOMOBILE a[] = {
{ "Ford", "Model T", 1908, 1000 },
{ "Honda", "Accord", 2022, 20000 }
};
saveData(a, sizeof(a) / sizeof(*a), 42);
}
or as an array of pointers:
#include <stdio.h>
typedef struct {
char make[50]; // ex: Ford, Honda, Toyota
char model[50]; // ex: Corolla, Camry
int yearBuilt; // ex: 2001, 2022
int cost; // ex: 20500, 8999, 15000
} AUTOMOBILE; // 108 bytes
// array of pointers
void saveData(AUTOMOBILE *a[], int eSize, int size) {
FILE *fp = fopen("binaryDocument.bin", "wb");
if (!fp) {
printf("\nCould not save the information to a binary file\n");
return;
}
fwrite(&size, sizeof(int), 1, fp);
fwrite(&eSize, sizeof(int), 1, fp);
for(unsigned i = 0; i < eSize; i++) {
fwrite(a[i], sizeof(**a), 1, fp);
}
fclose(fp);
}
int main() {
AUTOMOBILE *a[] = {
&(AUTOMOBILE) { "Ford", "Model T", 1908, 1000 },
&(AUTOMOBILE) { "Honda", "Accord", 2022, 20000 }
};
saveData(a, sizeof(a) / sizeof(*a), 42);
}
What you call size is usually referred to as max_size or capacity. eSize vs size is confusing. In either case, size is an artifact of your in memory representation so you don't need to persist that.
Prefer unsigned types when the value cannot be negative.
Types (AUTOMOBILE) are not by convention upper case (which is used for constants like enums and defined symbols).

Segmentation Error in C while trying to input

I am trying to make a C program to take in a list of movies and add to it with memory alloction and able to retrieve movies from the list as well using a txt file.
movies.txt
5
Mission Impossible
Action
4
2008
Up
Action
3
2012
I keep running into an error after running in the command line and when the menu comes up, whenever I input something it runs a seg fault. I don't have access to a debugger right now and I'm not exactly sure what's wrong although I assume its a problem with my pointers or memory alloc.
Can someone point me in the right direction?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// limit definition
#define LIMIT 999
//movie structure
struct movie
{
char name[100];
char type[30];
int rating;
int releaseDate;
};
//reads file
void readFile(FILE *fp,struct movie* movieList[],int *noOfReviews)
{
char buffer[100];
int counter = 0;
struct movie* newNode;
fgets(buffer,LIMIT,fp);
*noOfReviews = atoi(buffer); // number of reviews in buffer
printf("%d",*noOfReviews); //prints reviews
while((fgets(buffer,LIMIT,fp)!=NULL) || (*noOfReviews > 0)) //if null or reviews greater than zero
{
if(counter % 4 == 0)
{
struct movie* tmpNode = (struct movie*)malloc(sizeof(struct movie)); //allocates memory
movieList[counter] = tmpNode;
newNode = tmpNode;
*noOfReviews--; // --#ofreviews
}
//copys struc into buffer
switch(counter % 4 )
{
case 0:
strcpy(newNode->name,buffer);
break;
case 1:
strcpy(newNode->type,buffer);
break;
case 2:
newNode->rating = atoi(buffer);
break;
case 3:
newNode->releaseDate = atoi(buffer);
break;
default:
printf("Exception\n");
break;
}
counter++;
}
}
//searches list
int searchList(struct movie* movielist[],char movieName[],int noOfMovies)
{
int counter = 0;
while(noOfMovies--)
{
if(strcmp(movielist[counter]->name,movieName) == 0) // if string compares to name
{
return counter;
}
counter++;
}
return -1;
}
//compares strings of name
int nameStrCmp(const void *a, const void *b)
{
return (strcmp(((struct movie*)a)->name,((struct movie*)b)->name));
}
// compares rating strings
int ratingStrCmp(const void * a, const void * b)
{
return (((struct movie*)a)->rating - ((struct movie*)b)->rating);
}
//displays the structure
void display(struct movie* movieList[],int n)
{
int i;
struct movie* searchRslt;
for(i = 0; i < n; i++)
{
searchRslt = movieList[i];// search result index of movies list
//prints struct information
printf("name:%s\n type:%s\n rating:%d\n releaseDate:%d\n",searchRslt->name,searchRslt->type,searchRslt->rating,searchRslt->releaseDate);
}
}
//main function
int main(int argc, char *argv[])
{
char buffer[100];
int noOfReviews;
struct movie* movieList[1000];
struct movie *searchRslt;
char mName[100];
if(argc <= 1)
{
printf("invalid");
return 0;
}
FILE *fp = fopen(argv[1],"r");
readFile(fp,movieList,&noOfReviews);
while(1)
{
//case selection menu
int input;
printf("Enter 1 to search for a movie.\n");
printf("Enter 2 to display the list of movies by name.\n");
printf("Enter 3 to display the list of movies by rating.\n");
scanf("%d",&input);
switch(input)
{
case 1:
printf("Enter movie name to search:");
scanf("%s",mName);
int index = searchList(movieList,mName,noOfReviews);
if(index < 0)
printf("Not found!!\n"); // if movie not found
else // gets movies
{
searchRslt = movieList[index];
printf("name:%s\n type:%s\n rating:%d\n releaseDate:%d\n",searchRslt->name,searchRslt->type,searchRslt->rating,searchRslt->releaseDate);
}
break;
case 2:
qsort(movieList,noOfReviews,sizeof(struct movie),nameStrCmp);
display(movieList,noOfReviews);
break;
case 3:
qsort(movieList,noOfReviews,sizeof(struct movie),ratingStrCmp);
display(movieList,noOfReviews);
break;
default:
break;
}
}
}
A few formatting/readability/coding suggestions: (Some are just suggestions, others actually eliminate warnings.)
format. (mainly indention)
replace 'struct movie' with MOVIE everywhere. (see struct definition below)
initialize variables before use.
pay attention to buffer size in declaration and usage (fgets errors)
Compile with warnings on. (eg, with gcc use -Wall)
The following is limited to addressing each of these items, including new struct definition. The following compiles and builds without warnings or errors. It does not include debugging your code. (If can do a Beyond Compare (its free), between your original post and the edited version below, you can easily find where the edits are.)
(At the time of this post, there was no information provided about your input file, so further efforts were not made.)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// limit definition
#define LIMIT 999
//movie structure
typedef struct {
char name[100];
char type[30];
int rating;
int releaseDate;
}MOVIE;
//reads file
void readFile(FILE *fp,MOVIE* movieList[],int *noOfReviews)
{
char buffer[LIMIT];
int counter = 0;
MOVIE* newNode = {0};
fgets(buffer,LIMIT,fp);
*noOfReviews = atoi(buffer); // number of reviews in buffer
printf("%d",*noOfReviews); //prints reviews
while((fgets(buffer,LIMIT,fp)!=NULL) || (*noOfReviews > 0)) //if null or reviews greater than zero
{
if(counter % 4 == 0)
{
MOVIE* tmpNode = (MOVIE *)malloc(sizeof(MOVIE)); //allocates memory
movieList[counter] = tmpNode;
newNode = tmpNode;
*noOfReviews--; // --#ofreviews
}
//copys struc into buffer
switch(counter % 4 ) {
case 0:
strcpy(newNode->name,buffer);
break;
case 1:
strcpy(newNode->type,buffer);
break;
case 2:
newNode->rating = atoi(buffer);
break;
case 3:
newNode->releaseDate = atoi(buffer);
break;
default:
printf("Exception\n");
break;
}
counter++;
}
}
//searches list
int searchList(MOVIE* movielist[],char movieName[],int noOfMovies)
{
int counter = 0;
while(noOfMovies--)
{
if(strcmp(movielist[counter]->name,movieName) == 0) // if string compares to name
{
return counter;
}
counter++;
}
return -1;
}
//compares strings of name
int nameStrCmp(const void *a, const void *b)
{
return (strcmp(((MOVIE*)a)->name,((MOVIE*)b)->name));
}
// compares rating strings
int ratingStrCmp(const void * a, const void * b)
{
return (((MOVIE*)a)->rating - ((MOVIE*)b)->rating);
}
//displays the structure
void display(MOVIE* movieList[],int n)
{
int i;
MOVIE* searchRslt;
for(i = 0; i < n; i++)
{
searchRslt = movieList[i];// search result index of movies list
//prints struct information
printf("name:%s\n type:%s\n rating:%d\n releaseDate:%d\n",searchRslt->name,searchRslt->type,searchRslt->rating,searchRslt->releaseDate);
}
}
//main function
int main(int argc, char *argv[])
{
int noOfReviews;
MOVIE* movieList[1000];
MOVIE *searchRslt;
char mName[100];
if(argc <= 1)
{
printf("invalid");
return 0;
}
FILE *fp = fopen(argv[1],"r");
readFile(fp,movieList,&noOfReviews);
while(1)
{
//case selection menu
int input;
printf("Enter 1 to search for a movie.\n");
printf("Enter 2 to display the list of movies by name.\n");
printf("Enter 3 to display the list of movies by rating.\n");
scanf("%d",&input);
switch(input)
{
case 1:
printf("Enter movie name to search:");
scanf("%s",mName);
int index = searchList(movieList,mName,noOfReviews);
if(index < 0)
printf("Not found!!\n"); // if movie not found
else // gets movies
{
searchRslt = movieList[index];
printf("name:%s\n type:%s\n rating:%d\n releaseDate:%d\n",searchRslt->name,searchRslt->type,searchRslt->rating,searchRslt->releaseDate);
}
break;
case 2:
qsort(movieList,noOfReviews,sizeof(MOVIE),nameStrCmp);
display(movieList,noOfReviews);
break;
case 3:
qsort(movieList,noOfReviews,sizeof(MOVIE),ratingStrCmp);
display(movieList,noOfReviews);
break;
default:
break;
}
}
}

Overlapping and too long integer values in dynamic c structs

I have the following problem.
I need to create a list of savestates with dynamical length. That's why I decided to create a list by defining some structs and connecting dynamically created structs together to build a list of structs which can dynamically be extended and so on.
However, some things seem to not work at all. Here's the relevant code first:
saves.h:
#ifndef SAVES_H
#include<time.h>
#define SAVES_H
#define SVS_STRLEN 500
#define SVS_FILE "savefile.dat"
#define True 1
#define False 0
typedef struct SVS_STATE SVS_STATE;
typedef struct SVS_STATES SVS_STATES;
struct SVS_STATE {
int i_playfield[6][7];
int i_turn;
time_t i_time;
void *next;
};
struct SVS_STATES {
SVS_STATE *states;
int count;
int loaded;
};
void SVS_Add_State(int i_playfield[][7], int i_turn, time_t i_time);
void SVS_Debug_State(SVS_STATE *state);
void SVS_Format_State(SVS_STATE *state, char text[]);
SVS_STATE *SVS_Get_State(int number);
#endif
saves.c:
#include "saves.h"
#include<string.h>
#include<time.h>
SVS_STATE *SVS_Get_State(int number)
{
int i = 1;
SVS_STATE *state;
if (svs_current_state.loaded == False) return NULL;
if (number > svs_current_state.count) return NULL;
state = svs_current_state.states;
printf("printing state 1:");
SVS_Debug_State(state);
while( i < number)
{
i++;
state = (SVS_STATE*)(state->next);
printf("printing state %i:", i);
SVS_Debug_State(state);
}
return state;
}
void SVS_Format_State(SVS_STATE *state, char text[])
{
int i, j;
if (svs_current_state.loaded == False) return;
text[0] = '\0';
strcat(text, "{\0");
for (i = 0; i < X_SIZE; i++)
{
strcat(text, "{\0");
for(j = 0; j < Y_SIZE; j++)
{
strcat(text, "%i,\0");
sprintf(text, text, state->i_playfield[i][j]);
}
strcat(text, "}\0");
}
strcat(text, "};%i;%i\n\0");
sprintf(text, text, state->i_turn, state->i_time);
printf("\nFormatted state:%s\n", text);
}
void SVS_Debug_State(SVS_STATE *state)
{
char text[SVS_STRLEN];
SVS_Format_State(state, text);
printf("%s\n", text);
}
void SVS_Add_State(int i_playfield[][7], int i_turn, time_t i_time)
{
int i, j;
SVS_STATE *laststate, *newstate;
newstate = (SVS_STATE*)malloc(sizeof(SVS_STATE));
printf("adding state with time:%i\n", i_time);
if (svs_current_state.loaded == False) return;
for (i = 0; i < 6; i++)
for (j = 0; j < 7; j++)
newstate->i_playfield[i][j] = i_playfield[i][j];
newstate->i_turn = i_turn;
newstate->i_time = i_time;
newstate->next = NULL;
printf("initialized state:");
SVS_Debug_State(newstate);
if (svs_current_state.coun > 0)
{
laststate = SVS_Get_State(svs_current_state.count);
laststate->next = (void*)newstate;
} else
svs_current_state.states=newstate;
svs_current_state.count++;
}
int main()
{
int i_playfield[6][7] = {0};
// mark saves library as loaded here, but removed function, since it
// just sets svs_current_state.loaded (which is the global struct of
// type SVS_STATES) to 1
SVS_Add_State(i_playfield, 1, time(NULL));
i_playfield[0][0] = 2;
SVS_Add_State(i_playfield, 2, time(NULL));
return 0;
}
The actual problems I encountered while using the printf's and Debug_State calls in these functions:
- the i_time I give is printed out once in Add_State(), correctly. Means it is a legal time and stuff, but when printed out after creating the full state by using Format_State() the string is 50 percent to long and the last part is displayed twice, for example:
if the time is 12345678, it is displayed correctly while debugging in Add_State, but Format_State() displays 123456785678.
- second problem: the first state added works, more or less, fine. But after adding a second one, printing the first state (retrieved by using Get_State and formatted with Format_State) prints a mixture of two states, for example something like this:
state 1: {{0,0,0,0,0,0,0}{0,0,0,0,0,0,0}{0,0,0,0,0,0,0}...
{0,0,0,0,0,0}};1;123456785678
state 2: {{0,0,0,0,0,0}{0,0,0,0,0,0}...
{0,0,0,0,0,0}};2;1234567856785678,0}{0,0,0,0,0,0}...
Thanks for reading.
These calls
sprintf(text, text, ...
invoke undefined behaviour, as the target buffer and one of the other arguments overlap.
From the POSIX specs to sprintf():
If copying takes place between objects that overlap as a result of a call to sprintf() [...], the results are undefined.

String array searching in C

I'm trying to figure out how to search a list of names that are inputted into a string array. If the name entered is part of the original array, then the search function should return the position of the string in the array; if the string is not found, it should return -1. If -1 is returned then I want to be able to print out "not found", which doesn't seem like it would be too hard to figure out, but if the name is found, I want to be able to print out the position at which the name is found.
Here is my code, obviously I'm new to this, so I might have butchered how this is supposed to be done. The rest of my code seems to work fine, but it's this function that has me at a loss.
#include<stdio.h>
#include<conio.h>
#include<string.h>
#define MAX_NAMELENGTH 10
#define MAX_NAMES 5
void initialize(char names[MAX_NAMES][MAX_NAMELENGTH]);
int search(char names[MAX_NAMES][MAX_NAMELENGTH],int i,Number_entrys);
int main()
{
char names[MAX_NAMES][MAX_NAMELENGTH];
int i;
initialize(names);
search(names,i,Number_entrys);
search_result= search(names,i,Number_entrys);
if (search_result==-1){
printf("Found no names.\n");
}
if(search_result==0){
printf("Name found");
} getch();
return 0;
}
void initialize(char names[MAX_NAMES][MAX_NAMELENGTH])
{
int i, Number_entrys;
printf("How many names would you like to enter to the list?\n");
scanf("%d",&Number_entrys);
if(Number_entrys>MAX_NAMES){
printf("Please choose a smaller entry\n");
}else{
for (i=0; i<Number_entrys;i++){
scanf("%s",names[i]);
}
}
for(i=0;i<Number_entrys;i++){
printf("%s\n",names[i]);
}
}
int search(char names[MAX_NAMES][MAX_NAMELENGTH],int i)
{
int j, idx;
char name[MAX_NAMELENGTH];
printf("Now enter a name in which you would like to search the list for:");
scanf("%s", name);
for(x = 0; x < Number_entrys; x++) {
if ( strcmp( new_name, names[x] ) == 0 ){
/* match, x is the index */
return x;
}else{
return -1;
}
}
}
There are several problems here.
The purpose of search is to ask the user to enter a single name to be searched for. So why is
char new_name[MAX_NAMES][MAX_NAMELENGTH];
You need only a single array
char new_name[MAX_NAMELENGTH];
Then you have a loop you just go round once, so you don't need a loop
scanf("%s",new_name);
would be enough. This feels like you have copied the code you used to fill your array of names, but haven't really understood its essence.
Another problem is that you have no control on how long a name the user might enter. What would happen if the user typed a very long name? You'd over-fill the array and your program will probably crash and burn. Read this article to learn about how to control this.
To be really pedantic you should also check the return code from scanf, you are expecting to read one item so the return value should be 1, anything else would be an error.
Then you are trying to use strstr(), to look through an array of char arrays. The strstr documentation says that its purpose is to search for a substring within a string rather than search through an array of strings.
So instead just search the array by hand
/* what is i? the number of items used in the array? */
for(x = 0; x < i; x++) {
if ( strcmp( new_name, names[x] ) == 0 ){
/* match, x is the index */
return x;
}
}
/* here with no match */
return -1;
In your main
int search_result;
search_result = search( /* etc */ );
if ( search_result == -1 ) {
/* print "not found" here */
} else {
/* print something else */
}
You means like this:
int search(char names[MAX_NAMES][MAX_NAMELENGTH], int i)
{
int j, idx;
char name[MAX_NAMELENGTH];
printf("Now enter a name in which you would like to search the list for:");
scanf("%s", name);
idx = -1;
for(j = 0; j < i; j++){
if(strstr(names[i], name) != NULL){
idx = j;break;
}
}
return idx;
}
(8) ...
Maybe we'll turn it all around
'Cause it's not too late
It's never too late!! (8)
:) !
Sorry about the song ^_^... oh Well, I was having fun with this question for a couples of minutes, I hope this code help you out a little more, with regards:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* return array of indexs */
int*
search(const char *list, size_t slen, const char **arr_names, size_t arrlen)
{
int *arr_idx;
int j,i,idx;
i=idx=0;
arr_idx = malloc(sizeof(int)*arrlen+1);
if(!arr_idx)
exit(EXIT_FAILURE);
for(i=0; i<slen; i++) {
for(j=0; j<arrlen ; j++) {
if(!strncmp(&list[i], &arr_names[j][0], strlen(arr_names[j]))) {
arr_idx[idx] = j;
idx++;
}
}
}
arr_idx[idx] = -1; /* -1 terminated array */
if(!idx) {
free(arr_idx);
return NULL; /* found no names */
}
return arr_idx;
}
/* I'm a sick [something], nul terminated strings :P */
const char *string = "My favorite artists: ATB, Nujabes and Bonobo also Aphex Twins is nice, along with Trapt and Breaking Benjamin.\0";
const char *names[] = {"ATB\0", "Scifer\0", "Aphex\0", "Bonobo\0", "Nujabes\0", "Tipper\0"};
#define N_NAMES 6
int
main(void)
{
int i;
int *array;
array = search(string, strlen(&string[0]), names, N_NAMES);
if(!array) {
puts("Found no names.\n");
return EXIT_SUCCESS;
}
printf("Names found: ");
for(i=0; array[i]!=-1; i++)
printf("%s,", names[array[i]]);
printf("\b \n");
free(array); /* important */
/* system("pause"); */ /* NOTE: decomment this if you're on windows */
return EXIT_SUCCESS;
}
ran some tests:
~$ ./program
output
Names found: ATB,Nujabes,Bonobo,Aphex

Resources