qsort gives strange characters in the output - c

I want to sort employee data based on names. The sorting function works but provides strange characters in the output??
The last printf statement is the culprit I guess (bottom of the code)
If someone could help, that would be appreciated.
Thanks
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct
{
char name[25];
char firstname[25];
char job;
float hrs;
float rate;
} employee;
int main()
{
FILE *fp = fopen("employee.dat", "r");
employee staff[30];
int i = 0;
if (fp == NULL){
printf("not working\n");
exit(1);
}
fscanf(fp, "%s %s %c %f %f", staff[i].name, staff[i].firstname, &staff[i].job, &staff[i].hrs, &staff[i].rate);
while(!feof(fp))
{
printf("%s %s %c %4.1f %4.1f \n", staff[i].name, staff[i].firstname, staff[i].job, staff[i].hrs, staff[i].rate);
i++;
fscanf(fp, "%s %s %c %f %f", staff[i].name, staff[i].firstname, &staff[i].job, &staff[i].hrs, &staff[i].rate);
}
fclose(fp);
// qsort struct function for comparing names
int struct_cmp_by_name(const void *a, const void *b)
{
employee *ia = (employee *)a;
employee *ib = (employee *)b;
return strcmp(ia->name, ib->name);
}
int structs_len;
structs_len = sizeof(staff) / sizeof(employee);
// sort on names
qsort(staff, structs_len, sizeof(employee), struct_cmp_by_name);
//output with strange charaters???
for(i=0; i<structs_len; i++){
printf("%s %s %c %4.1f %4.1f \n", staff[i].name, staff[i].firstname, staff[i].job, staff[i].hrs, staff[i].rate);
}
return(0);
}
I am expecting a regular output of the printf statement.
The first printf works fine but the one after the qsort provides strange characters instead??

The most likely culprit of your problem is that you sort the whole array, even when maybe not all elements are initialized.
If the file contains less than the 30 elements you have for the array, parts of the array will be uninitialized with indeterminate contents (which may sometimes seem random or like "garbage"). You should not use those when sorting, only sort the data you actually have read from the file.
You have the number of valid and initialized elements in the array in the variable i which you should use instead:
qsort(staff, i, sizeof(employee), struct_cmp_by_name);
You have the same problem when printing the data: You print the whole array, including the uninitialized parts.
I suggest you create a new variable for the number of valid elements, suitable named, instead of the generic i that you now use.

Related

How to properly fscanf txt file in C

For example: #1 Tutti/Leeloo/853811356; N
And this is my code:
typedef struct{
int redni;
char prezime[50+1];
char ime[50+1];
char osobna[50+1];
char glasao[10];
} Biraliste;
int nBiraci=0;
while(fscanf(biralisteTxt, "%d %[^/]/%[^/]/%[^;];%[^\n]",
biraci[n].redni, biraci[n].prezime, biraci[n].ime, biraci[n].osobna, biraci[n].glasao ) == 5)
{
nBiraci++;
}
for(i=0;i<nBiraci;i++)
{
fprintf(statistikaTxt, "%d %s %s %s %s",
&biraci[i].redni, biraci[i].prezime, biraci[i].ime, biraci[i].osobna, biraci[i].glasao );
}
Can someone help mi with right fscanf and fprintf, and is it ok to fscanf redni with %d or it should be %s.
" #%d %[^/]/%[^/]/%[^;];%[^\n]" - this is the right answer, thank you
The following code fixes two problems.
scanf must get the address of the variable to fill, this &biraci...
the index must be nBiraci and not n, thus &biraci[nBiraci]...
there must be a # in front of %d
int nBiraci=0;
while(fscanf(biralisteTxt, " #%d %[^/]/%[^/]/%[^;];%[^\n]",
&biraci[nBiraci].redni, (char*)&biraci[nBiraci].prezime,
(char*)&biraci[nBiraci].ime, (char*)&biraci[nBiraci].osobna,
(char*)&biraci[nBiraci].glasao) == 5)
{
nBiraci++;
}

reading in a large amount of lines in C (csv files)

I have an input .csv file which is formatted like so:
10012,85
11981,100
10728,65
Where the first number is a student ID, followed by a grade on an exam. I need to be able to read an indefinite number of these lines, but I'm not sure how to in C. I couldn't format fscanf properly (kept giving me runtime errors/crashes). This is my attempt (note the struct is just how I'll be using the gathered data from the files later):
int main(int argc, char **argv) {
int i = 0;
FILE *inf;
struct List list = SLL_new();
for(int i = 1; i < argc; i++){
inf = fopen(argv[i], "r");
int studentID = 0;
int grade = 0;
if(inf == NULL){
printf("bad");
return 1;
}
fscanf(inf, "%d,%d", &studentID, &grade);
printf("%d, %d", studentID, grade);
}
}
}
This is my output when run with the input file at the top (pre-edit, when I was using fread):
C:\Users\witcher\Documents\NJIT\CS 288>a midterm01.csv
10012,85
11981,100
10728,65δ
I don't think this works with more lines, and regardless, the special character at the end is also confusing to me. I need to read these values as ints, but if I use fread then I need to cast them or something along those lines later.
Your reading ints, and trying to print strings;
fscanf(inf, "%d,%d", &studentID, &grade);
printf("%s, %s", studentID, grade);
Should be
fscanf(inf, "%d,%d", &studentID, &grade);
printf("%d, %d", studentID, grade);
To read the whole file try
while (2 == fscanf(inf, "%d,%d", &studentID, &grade))
{
printf("%d, %d", studentID, grade);
}
fclose(inf);

Reading from a text file and plotting using GNU libplot

I've made a program that reads from a file, and alphabetically sorts names contained within the file. The file contains planet names, mass, size, color, primary body, positions x,y,z and velocity x,y,z. I'm now trying to plot each planet using this file, but I'm unsure how to go about doing that. I'm using GNU libplot to plot the planets. I'm thinking that I need to use a loop and fscanfs to get the x and y coordinates (can omit Z for now) to plot each planet.
Here's my current code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NAMES 20
struct planets{ //sets up initial characters and doubles to place into body.
char primaryBody[NAMES];
char name[NAMES];
char color[NAMES];
double mass;
double size;
double posx, posy, posz;
double velx, vely, velz;
};
struct planets body[100];
int readData(FILE* fd){ //This reads the file solarsystem.txt and fills array
int current = 0;
char line[201];
char cmpline[2] = "#";
do{
fgets(line, 200, fd); // Makes sure that the number of bytes written dont overflow your character.
}while((strlen(line)<2)||(strncmp(line, cmpline, 1))==0);
sscanf(line, "%s %lf %s %lf %s", body[current].name, &body[current].mass, body[current].color, &body[current].size, body[current].primaryBody);
fscanf(fd, "%lf %lf %lf", &body[current].posx, &body[current].posy, &body[current].posz);
fscanf(fd, "%lf %lf %lf", &body[current].velx, &body[current].vely, &body[current].velz);
current++;
while(!feof(fd)){//Runs the loop until the end of the file is met.
fscanf(fd, "%s %lf %s %lf %s", body[current].name, &body[current].mass, body[current].color, &body[current].size, body[current].primaryBody);
fscanf(fd, "%lf %lf %lf", &body[current].posx, &body[current].posy, &body[current].posz);
fscanf(fd, "%lf %lf %lf", &body[current].velx, &body[current].vely, &body[current].velz);
current++;
}
return current;
}
void sortNames(int planetNames){ //traditional bubble sorting code, with slight modification.
struct planets temp[1];
for(int i=0; i<(planetNames);i++){
for(int j=0; j<(planetNames-1); j++){
if (strcmp(body[j].name, body[j+1].name)>0){
temp[0] = body[j];
body[j] = body[j+1];
body[j+1] = temp[0];
}
}
}
void printBodies(int sortNames){// code to print out the sorted file.
int planetNames = sortNames;
printf("Name Mass Color Size Primary Body\n");
printf("_____________________________________________\n");
for(int i=0; i<(planetNames); i++){
printf("%-8s %1.4E %-6s %.2lf %s\n", body[i].name, body[i].mass, body[i].color, body[i].size, body[i].primaryBody);
}
}
int main(int argc, char *argv[]){/*runs the different structs, and if file not available, will tell the user.*/
FILE *fd;
fd = fopen (argv[1], "r");
if(!fd){
printf("File not available, or user did not type file name.\n");
return 1;
}
int planetNames=readData(fd);
sortNames(planetNames);
printBodies(planetNames);
findMax(planetNames);
return 0;
}

Segfault - sscanf to arrays in C

I just need an extra set of eyes to help me find out why this code is segfaulting.
//------------------------Preprocessor Instructions. ------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#define NUMBER 128 //Maxmimum number of items/lines in file.
#define BUFFER 120 //Buffer length (For user input)
#define LENGTH 32 //Maximum length of lines in file.
//------------------------Global stuff. ---------------------------------------------
int iterations=0; //Will count number of times the calculation function is called.
int weight[NUMBER];
int value[NUMBER];
char object[NUMBER][LENGTH];
//------------------------Function Definitions. -----------------------------------------
void printarr();
//------------------------Printarr -- Array printing function. --------------------------
void printarr()
{
int i,j;
printf("\n");
printf("Weight \t Value \t Object \n");
for(i=0;i<4;i++){
printf("%d \t %d \t %s \n", weight[i], value[i], &object[i][0]);
}
}
//------------------------Main. ---------------------------------------------------------
int main(int argc, char **argv)
{
FILE *fp; //File pointer.
char buffer[BUFFER]; //Temporary storage
int result; //sscanf return value.
int capacity; //User input.
int i,j=0; //Loop counters.
//Command Line Argument Parsing: Assigns input value to capacity.
if (argc != 2){
printf("Usage: %s number. Max 1024. \n",argv[0]); //Usage: *program* *num*
return(1);
}
if (1 != sscanf(argv[1],"%d",&capacity)){
printf("Usage: %s number. Max 1024. \n",argv[0]);
return(1);
}
//File reading.
fp=fopen("knapsack.data","r");
if(NULL==fp){
printf("Error opening file. \n");
exit(0);
}
//Write to arrays.
while(NULL != fgets(buffer, BUFFER, fp)){
result=sscanf(buffer, "%d %d %s", &weight[i], &value[i], &object[i][0]);
i++;
}
//Print the arrays.
printarr();
fclose(fp);
}
According to GDB it segfaults when it hits the sscanf statement. But as far as I can tell there's nothing wrong with the way I'm accessing the locations... clearly I'm mistaken. Any help would be appreciated.
Edit: I was half right, fix this line:
result=sscanf(buffer, "%d %d %s", &weight[i], &value[i], &object[i][0]);
to look like this:
result=sscanf(buffer, "%d %d %s", &weight[i], &value[i], object[i]);
You are reading in a whole string, so you need to write to the c string location, in this case, object[i]. Also, init i for best practice (although gcc does init ints to zero if uninitialized, try it yourself and see).
Edit: Ignore the downvote, I am correct but I did make an error in forgetting to remove your second index, you can access a c string 2d array with object[i] or &object[i][0], both work. object[i] for accessing an entire string looks cleaner to me than using &object[i][0].

Edit/Modify & Delete of record from a Random Access File in C

The program should modify or delete a specific record according to employee id, in modifying part it writes the modified record as a new one at the end of the file, the deleting part works only once and then give me a segmentation fault.
Modifying:
How can I modify the code to rewrite the edited record in the same position?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdlib.h>
struct record_em{
int id;
char name[20];
int salary;
int age;
};
int main( void )
{
struct record_em employee;
FILE *fp;
int n;
int ch;
fp = fopen("empRecord.dat","rb+");
printf("Enter Id Number:\n");
scanf("%d",&n);
rewind(fp);
while (!feof(fp)){
fscanf(fp,"%d %s %d %d", &employee.id, employee.name, &employee.salary, &employee.age);
if (employee.id==n){
printf("%d %s %d %d \n",employee.id, employee.name, employee.salary,employee.age);
printf("\n Do you want to change the name ?\n");
scanf("%d",&ch);
if (ch==1){
printf("Enter new name:\n");
scanf("%s",employee.name);
}
printf("\n Do you want to change the salary ?(y/n)\n");
scanf("%d",&ch);
if ( ch==2 ){
printf("Enter new salary:\n");
scanf("%d",&employee.salary);
}
printf("\n Do you want to change the age ?(y/n)\n");
scanf("%d",&ch);
if ( ch==3 ){
printf("Enter new age:\n");
scanf("%d",&employee.age);
}
fseek(fp,-sizeof(employee),SEEK_CUR);
fprintf(fp, "%d %s %d %d\n", employee.id, employee.name, employee.salary, employee.age);
exit(0);
}
}
printf("Record Not Found \n");
return 0;
}
Deleting:
How can I modify the code to make it delete records as many times as I want?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdlib.h>
struct record_em{
int id;
char name[20];
int salary;
int age;
};
int main()
{
struct record_em employee;
FILE *fp, *ft;
int n;
fp = fopen("empRecord.dat","r");
ft = fopen("Temp.dat","wb+");
printf("\nEnter ID of employee to delete ");
scanf("%d",&n);
rewind(fp);
while (!feof(fp)){
fscanf(fp,"%d %s %d %d", &employee.id, employee.name, &employee.salary, &employee.age);
if(employee.id!=n){
fprintf(ft, "%d %s %d %d\n", employee.id, employee.name, employee.salary, employee.age);
}
}
fclose(fp);
fclose(ft);
remove("empRecord.dat");
rename("Temp.dat","EempRecord.dat");
return 0;
}
Here is the Key point of code:
void update(char filename[],char name[])
{
int records=0;
FILE *fp = fopen(filename,"rb+");
while(fread(&st,sizeof(st),1,fp)==1)
{
if(strcmp(name,st.name)==0)
{
printf("\nEnter new name: ");
scanf("%s",st.name);
printf("\nEnter new roll no.: ");
scanf("%d",&st.roll);
fseek(fp,sizeof(struct student)*records,SEEK_SET);//This is key line..
fwrite(&st,sizeof(st),1,fp);
}
records++; // in the while loop...
}
fclose(fp);
}
Below is the structure of student:
struct student{
int roll;
char name[20];
}st;
This is the general method to modify/update the record. You can use same syntax for your employee structure.
It's not good to manipulate a binary file using the C functions that are intended to be used to manipulate text files fprintf.
For example, in your code I see:
fseek(fp,-sizeof(employee),SEEK_CUR);
fprintf(fp, "%d %s %d %d\n", employee.id, employee.name, employee.salary, employee.age);
This will bring you problems, since you are traveling within your file as a binary file to then write characters on it. You shoud use the fwrite function instead.
My recommendation: check your whole program, define your persistence strategy and be consistent with this.
I think here is your problem, first you have a minus sign before the sizeofit's a bit weird to see that, and second the SEEK_CUR makes you move further than your current file is so take a look here fseek(), rewind()
fseek(fp,-sizeof(employee),SEEK_CUR); //This is not the definitive read below.
^------minus symbol. ^------- the type of seek.
I recommend You to do some modifications:
Use a common Formatted File to make your life easier, remember "The perfection is the simplicity".
Use SEEK_SET to use the relative position from the beginning of the file, second use the struct's size as the parameter for sizeof.
fseek( fp, sizeof( struct record_em), SEEK_SET );
Use the member id as the key of your sink and use a consecutive series of numbers, but obviously you should have created a file with 100, 1000 employers.
1 Andrew 20000 27
^ ^ ^ ^_____ age
| | |__________ salary ( I would have used double here)
| |_________________ name
|_____________________ id ( Key for the relative position from the beginning)
You will have to change your mind, and when you imagine "delete" a record you will write a white space (with exception of the key) example Imagine that the poor Andrew was fired and you will delete his record.
1 "Empty space" 0 0
^ ^ ^ ^______ age (0 = nothing)
| | |__________ salary (0 = nothing)
| |____________________ name ("" = nothing)
|____________________________ id ( Key for the relative position from the beginning)
PD:currently adding more information.
SEEK_CUR
offset is relative to the current file pointer position. So, in effect, you can say, "Move to my current position plus 30 bytes," or, "move to my current position minus 20 bytes."
eg. fseek(fp, -30, SEEK_CUR)
ref. http://beej.us/guide/bgc/output/html/multipage/fseek.html
I don't think he is wrong in using the negative of the sizeof() function.
But you would be better off using the sizeof(struct record_em) instead!

Resources