I have been working on reading data from a file, which contains student name and age in the format:
John
12
Jane
13
Julia
18
Here's the program I wrote:
#include <stdio.h>
#include <stdlib.h>
struct record{
char name[50];
int age;
};
int main(){
FILE *fp;
fp=fopen("sample2.txt","r");
struct record a[50];
int counter=1;
int i=0;
while (!EOF){
if (counter%2!=0){
fgets(a[i].name,50,fp);
counter++;
}
if (counter%2==0){
a[i].age=getw(fp);
counter++;
i++;
}
}
return 0;
}
However, on printing a[0].name, I am not getting expected output. Can someone help?
As already pointed out in the comments, EOF is a value defined in stdio.h and does not say anything about your file descriptor. I also would recommend you to use fscanf (As long you are sure that the names in the file are all of the correct length). fscanf takes a string similar to printf, specifying the elements you are expecting and returns the number of possible matches. Also it helps you with converting your data to the correct datatypes. So the code could look like this:
#include <stdio.h>
#include <stdlib.h>
struct record
{
char name[50];
int age;
};
int main ()
{
FILE *fp;
fp = fopen ("sample2.txt", "r");
struct record a[50];
int i = 0;
while (fscanf(fp, "%s\n%d\n", (char *) a[i].name, &a[i].age) > 0) {
i++;
}
printf("%s %d\n", a[1].name, a[1].age);
return 0;
}
Related
I newer in C language. I could not solve my problem. I have a input file, let's say input.txt. We know there are 4 column on every line. Nevertheless, we do not know how many lines are there. I give you sample input.txt:
Student,James,12,65
Teacher,Jane,23,60
Teacher,Michael,30,75
Student,Erric,15,73
First column can be 2 different things like student or teacher. 2nd column will be unique. No repeated names. 3rd column will be ages of the person's. 4th column will be weights. Also, I am trying to make 2D array. So, my goal is:
arrName = {{Student, James, 12, 65}, {Teacher,Jane,23,60}, {Teacher,Michael,30,75}, {Student, Erric, 15,73}}
I am trying to create like this array. The array must be dynamically. because we do not know how many lines are there. I could not split the every line by commas. I have tried strdot. how can I parse the lines with comma, and add them into 2D array? Also, I got confused about pointers. While creating 2D array, do we have to use like char **arrPtr;? Or using like *arrPtr is enough for creating 2D array?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define COLUMN 4 //We know that there are 4 column in chars.txt file.
int main(int argc, char const *argv[]) {
char *arrName;
int nameLines;
arrName = (char *) malloc( sizeof( char ) );
FILE *FileName;
FileName = fopen(argv[1], "r");
if (FileName == NULL) {
printf("The Name file could not open!\n");
exit(0);
}
else{
char c;
while ( (c == fgetc(FileName)) != EOF ) {
if (c == '\n') {
nameLines++;
}
}
printf("%d\n", nameLines);
}
return 0;
}
I could not continue after else statement. Can you help me?
You got a bunch of errors in your code like this for example.
while ( (c == fgetc(FileName)) != EOF ) { -> Comparison of constant -1 with boolean expression is always true
So let's start fresh. This is how I would read a comma separated file and dynamically allocate memory to an array of ´read´ objects. It's actually less lines of code then you would expect.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define COLUMNS 4
#define MAX_STRING_LENGTH 100 //Enter the maximum characters allowed as profession and name
typedef struct theDAta{
char type[MAX_STRING_LENGTH+1];
char name[MAX_STRING_LENGTH+1];
unsigned int age;
unsigned int weight;
}theData;
int main(int argc, char const *argv[]) {
theData* allDataPtr=malloc(1); //Pointer to all entries
theData currentData; //The current read data
int currentBlock=0; //the index currently 'active'
FILE *fp = fopen(argv[1], "r");
if (!fp) {
printf("The file you provided can't be read!\n");
exit(EXIT_FAILURE);
}
while (fscanf(fp, "%[^,],%[^,],%d,%d\n", currentData.type, currentData.name,¤tData.age,¤tData.weight) == COLUMNS) {
allDataPtr=realloc(allDataPtr, sizeof(theData)*(currentBlock+1));
if (!allDataPtr) {exit(EXIT_FAILURE);} //Memory allocation failure. Ok so here i lost my pointer to the previous memory.. However we let the OS garbage collect us.
memcpy(allDataPtr+currentBlock++, ¤tData, sizeof(currentData));
}
for (int x=0; x<currentBlock; x++) {
printf("Profession: %s\nName: %s\nAge: %d\nWeight: %d\n\n",allDataPtr[x].type,allDataPtr[x].name,allDataPtr[x].age,allDataPtr[x].weight);
}
fclose(fp);
free(allDataPtr);
return 0;
}
So what I do is to create a struct containing the stuff I want to populate from the file. Then I populate that object and extend the memory with the size of that object and then copy the read data to the end of that memory block.. That's basically it... Hope you get great grades :) !!
/Anders
EDIT
Was a bit bored this evening, so let's shave the code... And humm, well. This is not part of my official answer :-) but you could bling it like this (it's actually also skipping one layer of memory copy :) and the engine is 3 lines of C code if you define a line of C code delimiter as ';'->
typedef struct j{
char t[MAX_STRING_LENGTH+1];
char n[MAX_STRING_LENGTH+1];
unsigned int a;
unsigned int w;
}j;
int main(int argc, char const *argv[]) {
j* g;
int l=0;
FILE *h;
if((!(h=fopen(argv[1],"r"))||(!(g=malloc(sizeof(j))))))exit(-1);
while(fscanf(h,"%[^,],%[^,],%d,%d\n",g[l].t,g[l].n,&g[l].a,&g[l].w)==COLUMNS)if(!(g=realloc(g,sizeof(j)*(++l+1))))exit(-1);
for(int x=0;x<l;x++)printf("Profession: %s\nName: %s\nAge: %d\nWeight: %d\n\n",g[x].t,g[x].n,g[x].a,g[x].w);
fclose(h);
free(g);
return 0;
}
I supposed to perform a project which allocate N bytes of memory of struct person
and scanning f every person's name initial_money and some other variables
the problem for me when i run the code is that it is terminating at some point of taking input process and i don't why
also this problem faced me yesterday in code forces contest
#include <stdio.h>
#include <stdlib.h>
struct person
{
char name[15];
int initial_money;
int g;
int final_money;
int money;
};
int main()
{
int NP,i,j;
char target1[15];
scanf("%d",&NP);
struct person *p=malloc(NP*sizeof(struct person));
for(i=0;i<NP;i++)
{
scanf("%s",(p+i)->name);
}
for(i=0;i<NP;i++)
{
scanf("%s",target1);
for(j=0;j<NP;j++)
{
if((p+j)->name==target1)
{
scanf("%d%d",(p+j)->initial_money,(p+j)->g);
(p+j)->final_money=(p+j)->initial_money%(p+j)->g;
}
}
}
for(i=0;i<NP;i++)
{
printf("%s %d %d %d",(p+i)->name,(p+i)->initial_money,(p+i)->g,(p+i)->final_money);
}
return 0;
}
The scanf function need pointers for inputed values.
The line:
scanf("%d%d",(p+j)->initial_money,(p+j)->g);
Should be:
scanf("%d %d",&(p+j)->initial_money,&(p+j)->g);
When comparing strings you usually can't compare pointers directly:
if((p+j)->name==target1)
shoul be:
if(strcmp((p+j)->name, target1) == 0)
#include <stdio.h>
#include <stdlib.h>
struct account{
int accountId;
char *name;
double amount;
};
int main(int argc, char **argv)
{
FILE *file=fopen(argv[1],"r");
struct account *Ptr;
int i,j;
int size=0;
fscanf(file,"%d",&size);
if(size==0)
{
printf("Unable to open file");
return 0;
}
printf("%d",size);
Ptr=malloc(sizeof(struct account)*size);
for(i=0;i<size;i++)
{
fscanf(file,"%d%s%lf\n",&(Ptr+i)->accountId,(Ptr+i)->name,&(Ptr+i)->amount);
}
for(j=0;j<size;j++)
{
printf("%d%s%lf\n",((Ptr+j)->accountId),(Ptr+j)->name,((Ptr+j)->amount));
}
fclose(file);
free(Ptr);
return 0;
}
This is used to read in the input file
2
2 Harry 23.45
8 Sally 100.91
Somehow the code reads in the first 2 for size and the second 2 during the for loop but nothing else
Your code has undefined behavior, because you are reading data into an uninitialized pointer:
fscanf(file,"%d%s%lf\n",&(Ptr+i)->accountId,(Ptr+i)->name,&(Ptr+i)->amount);
// ^^^^
// This pointer is uninitialized ----------------------+
There are three ways to address this:
Make name an array, rather than a pointer, e.g. char name[MAX_NAME], or
Use malloc to allocate space to name before reading data into it.
Read into a temporary buffer, then malloc the exact number of chars.
This function is supposed to get a parameter as the pointer of a file and put all file into the struct anagram, then write it to another file. Right now the data only contains a.word, but it suppose to containst a.sorted too? I have check the a.sorted using printf
and it printf out the correct data, but why its not writing to the data file?
It still cant get the a.sorted even if i increase the count of the frwite
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include "anagrams.h"
#define SIZE 80
//struct
struct anagram {
char word[SIZE];
char sorted[SIZE];
};
void buildDB ( const char *const dbFilename ){
FILE *dict, *anagramsFile;
struct anagram a;
//check if dict and anagram.data are open
errno=0;
dict= fopen(dbFilename, "r");
if(errno!=0) {
perror(dbFilename);
exit(1);
}
errno=0;
anagramsFile = fopen(anagramDB,"wb");
char word[SIZE];
char *pos;
int i=0;
while(fgets(word, SIZE, dict) !=NULL){
//get ripe of the '\n'
pos=strchr(word, '\n');
*pos = '\0';
strncpy(a.word,word,sizeof(word));
//lowercase word
int j=0;
while (word[j])
{
tolower(word[j]);
j++;
}
/* sort array using qsort functions */
qsort(word,strlen(word), 1, charCompare);
strncpy(a.sorted,word,sizeof(word));
//printf(a);
fwrite(&a,1,strlen(word)+1,anagramsFile);
i++;
}
fclose(dict);
fclose(anagramsFile);
}
it suppose to contains data with a.sorted for example "10th 01ht"
data:
fwrite(&a,1,strlen(word)+1,anagramsFile); should have been fwrite(a.sorted,1,strlen(a.sorted)+1,anagramsFile); I assume the declaration of sorted as char sorted[SOME_LEN];
I have a segmentation fault...i'm not sure what's causing it. Also, when passing the member pname into the function get_names, am I doing this correctly, or is there a better way of doing this?
#include <stdio.h>
#define MAX_NAME 20
#define MAX_PLAYRS 16
typedef struct {
char pname[MAX_NAME];
int runs;
char how_out;
} Team_t;
Team_t player[MAX_PLAYRS];
Team_t *player_ptr[MAX_PLAYRS];
void get_names (int count, char *str);
int main (void) {
int i;
for (i = 0; i < MAX_PLAYRS; i++) {
get_names(i, &(*player[i].pname));
printf("Player: %s\n", player[i].pname);
}
}
void get_names (int count, char *str) {
FILE *inp;
char status;
inp = fopen("teamnames.rtf", "r");
status = fscanf(inp, "%s", str);
if (status == EOF) {
count = MAX_PLAYRS;
}
}
With your code unchanged, I get a segmentation fault if the file can't be opened properly (i.e. it's unreadable due to permissions, or it simply does not exist).
Here's a modified version of you function get_names():
void get_names(int count, char *str)
{
FILE *inp;
inp = fopen("teamnames.rtf", "r");
if (inp == NULL) {
perror("Failed");
return;
}
fgets(str, MAX_NAME, inp);
fclose(inp);
}
This would still read the first name 16 times, but it would tell you why it didn't manage to open the file. To read the next name from the file (rather than repeatedly the first name), open (and close) the file in the main() function instead.
Also, you might as well call get_names() like so:
get_names(i, player[i].pname);
No need to do that &(*...) thing you're doing.
And, finally, I hope that the teamnames.rtf file is not actually an RTF file, but a simple text file with a name on each line.
The problem comes from this line:
get_names(i, &(*player[i].pname));
Understanding pointers and dereferencing is one of the biggest adjustments to learning C if you are switching from another language. You're doing it wrong, and I think you should seek out a tutorial on the subject. Try http://www.cplusplus.com/doc/tutorial/pointers/ as a starting point.
Get a debugger to tell you what is wrong. Compile the code with debugging enabled (see you man page for your compiler) and run something like this:
gdb a.out core
Then you should be able to see which line made the code core dump. You could use idb as well, if you have the intle compiler installed. This is, of course, on *nix. If you are talking windows, use the VS debugger.
In addition do NOT use fscanf as it is unsafe. Use fgets instead.
There are many strange things. First thing is, it seems like the names are in a file, but what you are doing is in every iteration of your for loop, you call get_names which opens the file again, that is goes to the beginning of the file and you read the same name over and over again.
That is if you closed the file. Since you haven't closed the file, the file is already open and you keep reopening it (which could be the cause of your problem)
Another thing is, how can
if (status == EOF) {
count = MAX_PLAYRS;
}
Give you the current count? Regardless of the count of the players in the file, you are just setting it to MAX_PLAYERS.
Another thing is that count is an input to the function that is not a pointer, so setting it does not change the value outside the function (which is what I assumed you wanted).
Here is how I would do it with minimum change to your code:
#include <stdio.h>
#define MAX_NAME 20
#define MAX_PLAYRS 16
typedef struct {
char pname[MAX_NAME];
int runs;
char how_out;
} Team_t;
Team_t player[MAX_PLAYRS];
Team_t *player_ptr[MAX_PLAYRS];
void get_names (int count, char *str, FILE *inp);
int main (void) {
FILE *inp;
int i;
int count;
inp = fopen("teamnames.rtf", "r");
for (i = 0; i < MAX_PLAYRS; i++) {
get_names(&count, player[i].pname, inp);
printf("Player: %s\n", player[i].pname);
}
}
void get_names (int *count, char *str) {
char status;
status = fscanf(inp, "%s", str);
if (status == EOF) {
*count = MAX_PLAYRS;
}
}
Here is how I would do it more concisely:
#include <stdio.h>
#define MAX_NAME 20
#define MAX_PLAYRS 16
typedef struct {
char pname[MAX_NAME];
int runs;
char how_out;
} Team_t;
Team_t player[MAX_PLAYRS];
Team_t *player_ptr[MAX_PLAYRS];
int get_names (Team_t *team);
int main (void) {
get_names(player);
}
int get_names (Team_t *team) {
int i = 0;
FILE *inp;
inp = fopen("teamnames.rtf", "r");
while (i < MAX_PLAYRS && !feof(inp) {
fscanf(inp, "%s", team[i].pname);
printf("Player: %s\n", player[i].pname);
}
}
Note that the problems with fscanf, checking array boundaries etc are not the concern of this solution, but this rather gives you the idea of what to do not a code for you to copy-paste.