Reading from a text file and plotting using GNU libplot - c

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;
}

Related

For loop doesn`t work when add [^\n] to a scanf_s

This program should ask you to add member (people) to a struct and print them on a file but after the first for loop just stop working and jump over the name part. I just found that thing that allow you to add space to a string, tried it but no success...
I tried to remove it and it work without any problem so the [^\n] make something go wrong.
What is wrong ?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Staff {
char Surname[100];
char Name[100];
int age;
char spec[100];
int id;
} person;
void write();
void leggi();
void trova();
int main() {
write();
}
void write() {
int i = 0;
int n = 1;
int r;
FILE *fp;
fopen_s(&fp, "index.txt", "w+");
if (fp == NULL) {
printf("Failed to open file\n");
exit(1);
}
fprintf(fp, "%d\n", i);
for (i = 0; i < n; i++) {
printf("Surame:\n");
scanf_s("%[^\n]s", person.Surname, 100);
fprintf(fp, "%s\t\t", person.Surname);
//loop just get over the name part
printf("Name:\n"); //after the first loop
scanf_s("%s", person.Name, 100);
fprintf(fp, "%s\t", person.Name);
printf("Age:\n");
scanf_s("%d", &person.age);
fprintf(fp, "%d\t", person.age);
printf("Specialization\n");
scanf_s("%s", person.spec, 100);
fprintf(fp, "%s\n", person.spec);
printf("Want to enter another? 1=yes 0=no...\n");
scanf_s("%d", &r);
if (r == 1)
n = n + 1;
}
rewind(fp);
fprintf(fp, "%d\n", i);
fclose(fp);
}
There are multiple problems in your code:
you use the so called secure functions fopen_s, scanf_s etc, but you do not check the return values to detect invalid input. You should instead use standard functions, pass the appropriate arguments and check the return values.
using scanf_s is actually non portable: the scanf_s function defined in Annex K of the C Standard requires the length argument after the pointer to have size_t type, whereas the function with the same name in the Microsoft library uses type UINT, which has a different representation on 64-bit versions of their Windows OS. A classical case of the Embrace, enhance and extinguish strategy. In Standard C, one should write: scanf_s("%s", person.Name, (size_t)100) or better:
scanf_s("%s", person.Name, sizeof person.Name)
there is no need to open the output file for update with "w+", just use "w".
you rewind the stream pointer back to the beginning of file and overwrite the number of entries at the start of the file. This works as long as you have less than 10 entries, but beyond that, the number has more digits so some characters in the file will be corrupted. You could use a format with padding such as "%6d\n" which would allow for up to 1 million records without risks.
"%[^\n]s" is not a correct scanf format: you should just write "%[^\n]" or better " %99[^\n]" to skip initial white space and limit the input to 99 characters.
Here is a modified version:
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Staff {
char Surname[100];
char Name[100];
int age;
char spec[100];
int id;
};
void write(void);
void leggi(void);
void trova(void);
int main() {
write();
}
int flush_input(void) {
int c;
while ((c = getchar()) != EOF && c != '\n')
continue;
return c;
}
void write(void) {
int n = 0;
int r;
FILE *fp = fopen("index.txt", "w");
if (fp == NULL) {
fprintf("Failed to open file index.txt: %s\n",
strerror(errno));
exit(1);
}
fprintf(fp, "%6d\n", n);
for (;;) {
struct Staff person = { 0 };
printf("Surname:\n");
if (scanf(" %99[^\n]", person.Surname) != 1)
break;
flush_input();
fprintf(fp, "%s\t\t", person.Surname);
//loop just get over the name part
printf("Name:\n"); //after the first loop
scanf(" %99[^\n]", person.Name);
flush_input();
fprintf(fp, "%s\t", person.Name);
printf("Age:\n");
scanf("%d", &person.age);
flush_input();
fprintf(fp, "%d\t", person.age);
printf("Specialization\n");
scanf(" %99[^\n]", person.spec, 100);
flush_input();
fprintf(fp, "%s\n", person.spec);
n++;
printf("Want to enter another? 1=yes 0=no...\n");
if (scanf("%d", &r) != 1 || r != 1) {
flush_input();
break;
}
flush_input();
}
rewind(fp);
// update the entry count on 6 characters
fprintf(fp, "%6d\n", n);
fclose(fp);
}
Change the call of scanf below for entering strings by inserting a space in the beginning of the format string. For example instead of this call
scanf_s("%[^\n]s", person.Surname, 100);
(where the letter s must be removed from the format string) write
scanf_s(" %[^\n]", person.Surname, ( rsize_t )100);
^^^^^^^^
This allows to skip leading white space characters in the input buffer.
Pay attention to that changing the condition or the for loop the was as you are doing
for (i = 0; i < n; i++) {
//...
if (r == 1)
n = n + 1;
}
makes the code unclear. Instead of the for loop you could use do-while loop.

qsort gives strange characters in the output

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.

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);

storing dynamic arrays of a struct in text file in c language

hello this is my first year in learning c programming , i spent all day trying to figure this one out and now i have a head ache
anyway i just wanna keep this as simple as possible, here is a test code that i want to correct so i can understand how this works
what i wanna do is store a dynamic array of structure variables in a text file, and then reading the data from that text file into a dynamic array.
this is in c language
#include <stdio.h>
#include <stdlib.h>
struct student {
char nam[3]; // we store to this
char testname[3]; // we read to this
}*science[10];
int main() {
int i;
FILE *ptr=fopen("science_class","a");
for (i=0;i<3;i++){ //storing the infro from dynamic array into the file
e[i]=(science*)calloc(3,sizeof(char));
puts("enter name");
gets(science[i]->name);
fprintf(ptr,"%s",science[i]->name); }
for (i=0;i<3;i++){ // loading the info from the file to a dynamic array
fscanf(ptr,"%s",&science[i]->testname)
printf("name :%s \n",science[i]->testname) }
fclose(ptr);
}
I wrote a simple c program that has a car struct. The program simply reads data about cars into a dynamic array and writes it back to another file. Hope you understand the concepts:
#include<stdio.h>
#include<stdlib.h>
struct car
{
char name[20];
char color[20];
float mass;
int price;
};
typedef struct car Cars;
int main()
{
int i, n;
Cars *cars;
///////// READ:
FILE *in = fopen("cars_in.txt", "r");
fscanf(in, "%i", &n); //read how many cars are in the file
cars = (Cars*)malloc(n*sizeof(Cars)); //allocate memory
for (i = 0; i < n; ++i) //read data
{
fscanf(in, "%s", cars[i].name);
fscanf(in, "%s", cars[i].color);
fscanf(in, "%f", &cars[i].mass);
fscanf(in, "%i", &cars[i].price);
}
fclose(in);
///////////// WRITE:
FILE *out = fopen("cars_out.txt", "w");
fprintf(out, "%d\n", n);
for (i = 0; i < n; ++i)
{
fprintf(out, "%s ", cars[i].name);
fprintf(out, "%s ", cars[i].color);
fprintf(out, "%f ", cars[i].mass);
fprintf(out, "%i\n", cars[i].price);
}
fclose(out);
free(cars);
return 0;
}
and here is some data that you should put in a cars_in.txt:
5
BMW red 1500 80000
Opel black 950 15000
Mercedes white 2500 100000
Ferrari red 1700 2000000
Dodge blue 1800 750000
EDIT:
I simply changed fscanf to scanf and works fine. Be careful when you enter the data: first you have to tell how many cars you want to add so malloc can reserve space, after you enter the car's name->color->mass->price separated with white characters (enter, space, tab).
Just change the read section, the rest of the code remains the same:
///////// READ FROM KEYBOARD
scanf("%d", &n); // first we have to know the number of cars
cars = (Cars*)malloc(n*sizeof(Cars)); //allocate memory
for (i = 0; i < n; ++i) //read data -> be careful: you have to keep the order
{
scanf("%s", cars[i].name);
scanf("%s", cars[i].color);
scanf("%f", &cars[i].mass);
scanf("%i", &cars[i].price);
}

C parsing fgets() char array into multiple variables with sscanf using structures

In this program it compiles but i get segmentation fault, sscanf(str, "%d %s %s %d %f", &pos, z[pos-1].city, z[pos-1].state, &z[pos-1].population, &z[pos-1].growth); its because this line z[pos-1].city, z[pos-1].state, doesnt have & but when i add that i get warning: format â%sâ expects type âchar *â, but argument 4 has type âchar (*)[200]â.
i'm sure there is another way of doing this, i need to use structure, read in file store info into an array of a structure then displaying the array. the printf works just storing the city and state into char array.
I commented the area where i tried to initialize to array and had an incompatable type with the char array value all three: a, 'a', "a".
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct{
int rank;
char city[200];
char state[50];
int population;
float growth;
}city_t;
void read_data(city_t *z)
{
FILE *inp;
inp = fopen("cities.dat", "r");
char str[256];
int pos = 0;
if(inp==NULL)
{
printf("The input file does not exist\n");
}
else
{
/*reads and test until eof*/
while(1)
{
/*if EOF break while loop*/
if(feof(inp))
{break;}
else
{
/*read in a number into testNum*/
//fscanf(inp, "%d", &testNum);
fgets(str,sizeof(str),inp);
sscanf(str, "%d %s %s %d %f", &pos, z[pos-1].city, z[pos-1].state, &z[pos-1].population, &z[pos-1].growth);
z[pos-1].rank = pos;
}
}
}
fclose(inp);
}
void print_data(city_t *z, int size)
{
int i;
printf("rank\tcity\t\tstate\tpopulation\t\tgrowth\n");
for(i=0;i<size;i++)
{
printf("%d\t%s\t\t%s\t\%d\t\t%f\n", z[i].rank, z[i].city, z[i].state, z[i].population, z[i].growth);
}
}
int main()
{
int i;
city_t cities[10];
/*for(i;i<10;i++)
{
cities[i].rank = 0;
cities[i].city = "a";
cities[i].state = "a";
cities[i].population = 0;
cities[i].growth = 0.00;
}*/
read_data(&cities[0]);
print_data(&cities[0], 10);
return(0);
}
{
dat file
1 New_York NY 8143197 9.4
2 Los_Angeles CA 3844829 6.0
3 Chicago IL 2842518 4.0
4 Houston TX 2016582 19.8
5 Philadelphia PA 1463281 -4.3
6 Phoenix AZ 1461575 34.3
7 San_Antonio TX 1256509 22.3
8 San_Diego CA 1255540 10.2
9 Dallas TX 1213825 18.0
10 San_Jose CA 912332 14.4
}
In read_data, you scan into z[pos-1].... where pos starts at 0. So you will be writing beyond (before) the extend of the array.
Just do a global replace of pos-1 with pos and also increment pos; you can also use fscanf, so your reading can be:
for (int pos=0; !feof(inp); ++pos)
{
fscanf(inp, "%d %s %s %d %f",
&z[pos].rank,
z[pos].city,
z[pos].state,
&z[pos].population,
&z[pos].growth);
}

Resources