I am stuck at a C language problem in which I was supposed to input name and age of players from their respective files and output the same for a specific number of players which will be taken input (OR -1 to exit). The problem has to be solved using structures. I have attached the output I am getting along with the data that the age and name files contained.
Can someone explain to me where I am doing wrong?
Any help in optimisation too will be really helpful. Thanks!
Following is the code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Cricket_Player_DataBase
{
char name[30];
int score;
char role[11];
int age;
int wickets;
};
int main()
{
FILE *nf_ptr , *af_ptr; //nf_ptr is pointing to name.txt file | af_ptr is pointing to age.txt file
nf_ptr = fopen("name.txt","r");
af_ptr = fopen("age.txt","r");
int number_of_players = 0; //will be used to fix the size of array of structures
// following code is used just to count number of players, upto the point where 'HERE' is written
int temp, border_check = 0;
while((temp = fgetc(af_ptr)) != EOF)
{
if(temp == '\n')
{
++number_of_players;
border_check = 0;
}
else border_check++;
}
if(border_check > 0) ++number_of_players;
af_ptr = fopen("age.txt","r");
// HERE
struct Cricket_Player_DataBase players[number_of_players];
int temp_age , zero = 0 ;
char temp_char[30] , ch ;
for(int i=0; i < number_of_players; ++i)
{
temp_age = fgetc(af_ptr);
players[i].age = temp_age;
while((ch = fgetc(nf_ptr)) != EOF)
{
if(ch == '\n')
{
strncpy(players[i].name , temp_char , zero+1);
zero = 0;
break;
}
else
{
temp_char[zero] = ch;
zero++;
}
}
}
int input;
printf("Enter number of players you want to see the data of OR type -1 to exit : ");
scanf("%d", &input);
if(input > 0)
{
for(int i = 0; i < input; ++i)
{
printf("Data of player #%d is \nName : %s\nAge : %d\n", i+1 , players[i].name , players[i].age);
}
}
fclose(nf_ptr);
fclose(af_ptr);
return 0;
}
Output I got.
Name file was this.
Age file was this.
You're opening af_ptr without closing it. It could cause problems. If you want to open the same file again, use function rewind(file) or fclose it and open it again.
This is because you have made an assumption that the end of each name and age in your text files is a line feed character '\n'. Assuming you have created your text files in a windows machine, the line endings are \r\n, that is - a carriage return character followed by a line feed. Using Hex Editor Neo, here's what your files' contents would look like.
Your name.txt file
Your age.txt file
Notice the line endings - '0x0d' is a carriage return '\r' and '0x0a' is a line feed '\n'. Modify your program to take this into account.
Read more about line endings here: https://blog.codinghorror.com/the-great-newline-schism/
Related
i'm trying to read variables from a txt file.
The file .txt is like:
john 10
mark 230
peter 1
I would like to transfer and save this values in an array, for example array[0] = 10, array[1] = 230 etc without minding of names. I pasted my code below and I would like to know how can i edit it using this code below
int conf[4], i = 0, c;
FILE *file_conf;
file_conf = fopen("conf.txt", "r");
if(file_conf == NULL){
fprintf(stderr, "Error\n");
exit(EXIT_FAILURE);
} else {
while((c = fgetc(file_conf)) != EOF) {
fscanf(file_conf, "%d", &conf[i]);
printf("%d\n", conf[i]);
i++;
}
}
You should not be using fgetc() at all--that gets a single character. Instead, add the name format to your fscanf(), something like this:
char name[100];
fscanf(file_conf, "%s %d", name, &conf[i]);
You can prefix scanf() family conversion specifiers with * to suppress assignment. Note that in the posted code, failure to check the value returned from fscanf() could lead to problems with malformed input. Also, the input loop should exit when the array index i grows too large to avoid buffer overflow. The following code exits the loop when i is too large, or when malformed input is encountered:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int conf[4], i = 0;
FILE *file_conf;
file_conf = fopen("conf.txt", "r");
if(file_conf == NULL){
fprintf(stderr, "Error\n");
exit(EXIT_FAILURE);
} else {
while(i < 4 && fscanf(file_conf, "%*s%d", &conf[i]) == 1) {
printf("%d\n", conf[i]);
i++;
}
}
fclose(file_conf);
return 0;
}
Output using using the posted sample input:
10
230
1
Hi,
I need to count the usage of alphabetical characters in some plain text file. This is what i have came with. Basically just run through the text file and compare each character with the ASCII value of specific searched character.
When I run it, all I can see is just the first printf() string and just error of terminated status when I close the console.
I do have a text.txt file in same folder as the .exe file but I can't see anything.
Not sure if just my syntax is bad or even semantics.
Thx for help! :-)
#include <stdio.h>
#include <stdlib.h>
#define ASCIIstart 65
#define ASCIIend 90
void main(){
FILE *fopen(), *fp;
int c;
unsigned int sum;
fp = fopen("text.txt","r");
printf("Characters found in text: \n");
for (int i = ASCIIstart; i <= ASCIIend; i++){
sum = 0;
c = toupper(getc(fp));
while (c != EOF){
if (c == i){
sum = sum++;
}
c = toupper(getc(fp));
}
if (sum > 0){
printf("%c: %u\n",i,sum);
}
}
fclose(fp);
}
Instead of looking up the entire file for each character, you could do
FILE *fp;
int c, sum[ASCIIend - ASCIIstart + 1]={0};
fp = fopen("file.txt,"r");
if(fp==NULL)
{
perror("Error");
return 1;
}
int i;
while( (c = toupper(getc(fp)))!= EOF)
{
if(c>=ASCIIstart && c<=ASCIIend)
{
sum[c-ASCIIstart]++;
}
}
for(i=ASCIIstart; i<=ASCIIend; ++i)
{
printf("\n%c: %d", i, sum[i-ASCIIstart]);
}
You must check the return value of fopen() to ensure that the file was successfully opened.
There's an array sum which holds the the number of occurrences of each character within the range denoted with ASCIIend and ASCIIstart macros.
The size of the array is just the number of characters whose number of occurrences is to be counted.
sum[c-ASCIIstart] is used because the difference between the ASCII value (if the encoding is indeed ASCII) of c and ASCIIstart would give the index associated with c.
I don't know what you meant with FILE *fopen(), fp; but fopen() is the name of a function in C used to open files.
And by
FILE *fopen(), *fp;
you gave a prototype of a function fopen().
But in stdio.h, there's already a prototype for fopen() like
FILE *fopen(const char *path, const char *mode);
yet no errors (if so) were shown because fopen() means that the function can have any number of arguments. Have a look here.
Had the return type of your FILE *fopen(); were not FILE * or if it were shown to other parameter types like int, you would definitely have got an error.
And, void main() is not considered good practice. Use int main() instead. Look here.
You can use a character array and parse the file contents with one time traversal and display the array count finally.
#include <stdio.h>
#include<ctype.h>
void main(){
FILE *fopen(), *fp;
int c;
fp = fopen("test.txt","r");
printf("Characters found in text: \n");
char charArr[26]= {0};
c = toupper(fgetc(fp));
while(c!=EOF) {
charArr[c-'A']=charArr[c-'A']+1;
c = toupper(fgetc(fp));
}
fclose(fp);
for(int i=0;i<26;i++){
printf("\nChar: %c | Count= %d ",i+65,charArr[i]);
}
}
Hope this helps!!
because after first time you are end of the file.
and your c = toupper(getc(fp)); returning -1 after that.
For counting just one character, you are reading the whole file and repeating this for each and every character. Instead, you can do:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define ASCIIstart 65
#define ASCIIend 90
int main(){
FILE *fp;
int c, i;
int alphabets[26] = {0};
fp = fopen("text.txt","r");
if (fp == NULL){
fprintf (stderr, "Failed to open file\n");
return -1;
}
while ((c = toupper(fgetc(fp))) != EOF){
if (c >= ASCIIstart && c <= ASCIIend)
alphabets[c - ASCIIstart]++;
}
fclose(fp);
fprintf(stdout, "Characters found in text: \n");
for (i = 0; i < 26; i++)
fprintf (stdout, "%c: %d\n", i+ASCIIstart, alphabets[i]);
return 0;
}
TLDR
Working with your code, your loops are inside-out.
I'll answer in pseudo-code to keep the concepts straightforward.
Right now you are doing this:
FOR LETTER = 'A' TO 'Z':
WHILE FILE HAS CHARACTERS
GET NEXT CHARACTER
IF CHARACTER == LETTER
ADD TO COUNT FOR CHAR
END IF
END WHILE
END FOR
The problem is you are running through the file with character 'A' and then reaching the end of file so nothing gets done for 'B'...'Z'
If you swapped this:
WHILE FILE HAS CHARACTERS
GET NEXT CHARACTER
FOR LETTER = 'A' TO 'Z'
IF LETTER = UCASE(CHARACTER)
ADD TO COUNT FOR LETTER
END IF
END FOR
END WHILE
Obviously doing 26 checks for each letter is too much so perhaps a better approach.
LET COUNTS = ARRAY(26)
WHILE FILE HAS CHARACTERS
CHARACTER := UCASE(CHARACTER)
IF CHARACTER >= 'A' AND CHARACTER <= 'Z'
LET INDEX = CHARACTER - 'A'
COUNTS[INDEX]++
ENDIF
END WHILE
You can translate the pseudo code to C as an exercise.
Rewind the pointer to the beginning of the file at the end of your for loop?
This has been posted before: Resetting pointer to the start of file
P.S. - maybe use an array for your output values : int charactercount[pow(2,sizeof(char))] so that you don't have to parse the file repeatedly?
edit: was missing pow()
I searched through and didn’t get a quite working answer. Although I know that still there might be plenty of answers out there. Honestly I couldn’t find it as I am a beginner to C/C++ .
My problem is I have a text file which has data on it separated by pipes('|'). Actually a log file. In each entry things are separated by pipes('|') and each entry is separated by new line('\n')its really lengthy. So I wanted to do is that when user gives a sequence sequence=[2,5,7] the function should be able to read that array and give only the things starting with that pipe position. So here It should give 2nd ,5th, and 7th things in to a text file. down here is the code I used. It doesnt work for some reason I can't find. It gives the resulting text file printed out only with the '\n' and no more.Its more thant the entries in the file too.
minorSeparatorChar is the charactor given as '|'
majorSeparatorChar is the charactor given as '\n'
inFile Input text file
outFile output text file
minSepCount minor separator count
majSepCount major separator count
sequence is a global const int array
void getFormattedOutput(char * inFile, char * outFile, char minorSeparatorChar,char majorSeparatorChar){
FILE *readFile,*writeFile;
int charactor=0, minSepCount=0, i=0,majSepCount = 0;
int flagMin = 0;
char charactorBefore = NULL;
readFile = fopen(inFile,"r"); // opens the file for reading
writeFile = fopen(outFile,"w"); // opens the file for writing
if (readFile==NULL || writeFile == NULL){
printf("\nFile creation is not a sucess, Exiting program..\n");
exit(0);
}
while(charactor!=EOF){
charactorBefore = charactor;
if (charactor==minorSeparatorChar)
flagMin=1;
charactor = fgetc(readFile);
if(charactorBefore == minorSeparatorChar){
flagMin = 0;
if (minSepCount==sequence[i]){
fputc(charactor,writeFile);
continue;
}
i++;
minSepCount++;
}
else if (charactorBefore == majorSeparatorChar){
minSepCount=0;
i=0;
majSepCount++;
fputc('\n',writeFile);
}
else{
if(flagMin==1)
fputc(charactor,writeFile);
continue;
}
}
fclose(readFile);
fclose(writeFile);
}
for example if the input file has
33|333|67|787|7889|9876554|56
20151001|0|0|0|0||94|71
1|94|71|1|94|71|1
and if I give sequence [2,5,6]
It should print to out file as
67 9876554 56
0 94 71
71 71 1
I ultimately concluded that there were too many flags and controls and variables in your code and that I couldn't make head or tail of what they were up to, and decided to rewrite the code. I couldn't see in your code how you knew how many fields were in the sequence, for example.
I write in C11 (C99), but in this program, that simply means that I declare variables when they're needed, not at the top of the function. If it's a problem (C89/C90), move the declarations to the top of the function.
I also find that the names used were so long that they obscured the purpose of the variables. You may think I've gone too far in the other direction; more significantly, your professor (teacher) may think that. So be it; names are fungible and global search and replace works well.
I also don't see how your code is supposed to interpolate semi-arbitrary numbers of blanks between the fields, so I've actually ducked the issue. This code outputs the field separator (minor_sep — a length reduction of minorSeparatorChar) and the record separator (major_sep — reduced from majorSeparatorChar) at the appropriate points.
I note that field numbers start with field 0 in your code. I'm not convinced your code would ever output data from field 0, but that is somewhat tangential given the rewrite.
I ended up with:
#include <stdio.h>
#include <stdlib.h>
static const int sequence[] = { 2, 5, 7 };
static const int seqlen = 3;
static
void getFormattedOutput(char *inFile, char *outFile, char minor_sep, char major_sep)
{
FILE *ifp = fopen(inFile, "r"); // opens the file for reading
FILE *ofp = fopen(outFile, "w"); // opens the file for writing
if (ifp == NULL || ofp == NULL)
{
printf("\nFile creation is not a success, Exiting program..\n");
exit(0);
}
int c;
int seqnum = 0;
int fieldnum = 0;
while ((c = getc(ifp)) != EOF)
{
if (c == major_sep)
{
putc(major_sep, ofp);
fieldnum = 0;
seqnum = 0;
}
else if (c == minor_sep)
{
if (seqnum < seqlen && fieldnum == sequence[seqnum])
{
putc(minor_sep, ofp);
seqnum++;
}
fieldnum++;
}
else if (fieldnum == sequence[seqnum])
fputc(c, ofp);
}
fclose(ifp);
fclose(ofp);
}
int main(void)
{
getFormattedOutput("/dev/stdin", "/dev/stdout", '|', '\n');
return 0;
}
When I run it (I called it split, though it isn't a good choice since there is also a standard command split), I get:
$ echo "fld0|fld1|fld2|fld3|fld4|fld5|fld6|fld7|fld8|fld9" | ./split
fld2|fld5|fld7|
$ echo "fld0|fld1|fld2|fld3|fld4|fld5|fld6" | ./split
fld2|fld5|
$
The only possible objection is that there is a field terminator rather than a field separator. As you can see, a terminator is not hard to implement; making it into a separator (so there isn't a pipe after the last field on the line, even when the line doesn't have as many fields as there are elements in the sequence — see the second sample output) is trickier. The code needs to output a separator when it reads the first character of a field that should be printed after the first such field. This code achieves that:
#include <stdio.h>
#include <stdlib.h>
static const int sequence[] = { 2, 5, 7 };
static const int seqlen = 3;
static
void getFormattedOutput(char *inFile, char *outFile, char minor_sep, char major_sep)
{
FILE *ifp = fopen(inFile, "r"); // opens the file for reading
FILE *ofp = fopen(outFile, "w"); // opens the file for writing
if (ifp == NULL || ofp == NULL)
{
printf("\nFile creation is not a success, Exiting program..\n");
exit(0);
}
int c;
int seqnum = 0;
int fieldnum = 0;
int sep = 0;
while ((c = getc(ifp)) != EOF)
{
if (c == major_sep)
{
putc(major_sep, ofp);
fieldnum = 0;
seqnum = 0;
sep = 0;
}
else if (c == minor_sep)
{
if (seqnum < seqlen && fieldnum == sequence[seqnum])
seqnum++;
fieldnum++;
sep = minor_sep;
}
else if (fieldnum == sequence[seqnum])
{
if (sep != 0)
{
putc(sep, ofp);
sep = 0;
}
putc(c, ofp);
}
}
fclose(ifp);
fclose(ofp);
}
int main(void)
{
getFormattedOutput("/dev/stdin", "/dev/stdout", '|', '\n');
return 0;
}
Example run:
$ {
> echo "Afld0|Afld1|Afld2|Afld3|Afld4|Afld5|Afld6|Afld7|Afld8|Afld9"
> echo "Bfld0|Bfld1|Bfld2|Bfld3|Bfld4|Bfld5|Bfld6|Bfld7|Bfld8|Bfld9"
> echo "Cfld0|Cfld1|Cfld2|Cfld3|Cfld4|Cfld5|Cfld6|Cfld7|Cfld8|Cfld9"
> echo "Dfld0|Dfld1|Dfld2|Dfld3|Dfld4|Dfld5|Dfld6|Dfld7|Dfld8|Dfld9"
> echo "Efld0|Efld1|Efld2|Efld3|Efld4|Efld5|Efld6|Efld7|Efld8|Efld9"
> } | ./split
|Afld2|Afld5|Afld7
|Bfld2|Bfld5|Bfld7
|Cfld2|Cfld5|Cfld7
|Dfld2|Dfld5|Dfld7
|Efld2|Efld5|Efld7
$
this is a program that is giving me many headaches, but I am tackling it!
I want to create a program that basically reads a file called message.txt which would have some texts with a message, let's say: ''Hello I am a program'' and then encrypts that message and puts it in a file called encryptMessage.txt, additionally it will save the key used for the user in the file key.txt. Now this is what I have done so far.
That part is already finished. There's only one last thing that I need to do.
The file message.txt has more than one line. For example:
hello I like programming
this is a test
to see if this program
can read and encrypt many lines
I want the program to read all those lines and then encrypt them and save them in encryptMessage.txt, such as this (let's suppose the key is 3):
khoor L olnh surjudpplqj
wklv lv d whvw
wr vhh wklv surjudp
fdq uhdg dqg hgfu|sw pdq| olqhv
However, I do not know how to make it work. I know I need to use a loop and !feof function or something like that. But I sincerely do not know how to implement, do you have any idea? Thank you very much!
#include <stdio.h>
#include <ctype.h>
#define MAXSIZE 100
int main(void)
{
FILE *message;
FILE *encryptMessage;
FILE *key;
message = fopen("message.txt", "r");
encryptMessage = fopen("encryptMessage.txt", "w");
key = fopen("key.txt", "w");
if ((message == NULL) || (encryptMessage == NULL) || (key == NULL))
{
printf("Error reading file!!!\n");
return 1;
}
int userKey;
char sentence[MAXSIZE];
char q[MAXSIZE];
int i = 0;
printf("Input the text that you want to encrypt:\n> ");
fgets(sentence, 99, message);
// printf("\nThe string that you wrote is:\n%s\n\n", sentence);
printf("Input the key:\n");
scanf("%d", &userKey);
fprintf(key, "%d", userKey);
//printf("\nThe key that you selected is: %d\n\n", userKey);
for(i = 0; sentence[i] != '\0'; ++i)
{
if( ( isupper(sentence[i]) ) || ( islower(sentence[i]) ) )
{
q[i] = sentence[i] + (char)userKey;
}
else
{
q[i] = (sentence[i]);
}
}
q[i] = '\0';
printf("%s", q);
fprintf(encryptMessage, "%s", q);
fclose(encryptMessage);
fclose(key);
fclose(message);
return 0;
}
Here's how you can read entire file:
while(fgets(sentence, MAXSIZE - 1, message)) {
// do something with sentence
}
Here is modified source code: http://pastebin.com/KxAe9KcS
The code is supposed to read a user-inputted text file name, copy every character into a multidimensional array, then display it with standard output. It compiles, but produces unintelligible text. Am I missing something?
for (i = 0; i < BIGGEST; i++) {
for (j = 0; j < BIGGESTL; j++) {
if (fgetc(array, fp) ) != EOF)
array[i][j] = c;
else array[i][j] = '\0'
}
fclose(fp);
return 0;
}
You stop filling the array when you encounter EOF, but you print the full array out no matter what.
If the data read from the file is smaller than the input array, you will read that data in and then print that data out, plus whatever random characters were in the memory locations that you do not overwrite with data from the file.
Since the requirement seems to be to print text data, you could insert a special marker in the array (e.g. '\0') to indicate the position where you encountered EOF, and stop displaying data when you reach that marker.
You had better read each line from file
For example:
int i = 0;
while(fgets(text[i],1000,fp))
{
i++;
}
Though the question is edited and only part of the code is left in question. I am posting more than what is required for the question at the moment.
Reason being, there can be numberous improvements to originally posted full code.
In main() function:
You need to check for the argc value to be equal to 2 for your purpose and only then read in value of argv[1] . Else if program executed without the command-line-argument which is file_name in this case, invalid memory read occurs, resulting in segmentation fault if you read in argv[1].
In read_file_and_show_the contents() function:
Stop reading file if end of file is reached or maximum characters is read and store in the character array.
Below Program will help you visualize:
#include <stdio.h>
/*Max number of characters to be read/write from file*/
#define MAX_CHAR_FOR_FILE_OPERATION 1000000
int read_and_show_the_file(char *filename)
{
FILE *fp;
char text[MAX_CHAR_FOR_FILE_OPERATION];
int i;
fp = fopen(filename, "r");
if(fp == NULL)
{
printf("File Pointer is invalid\n");
return -1;
}
//Ensure array write starts from beginning
i = 0;
//Read over file contents until either EOF is reached or maximum characters is read and store in character array
while( (fgets(&text[i++],sizeof(char)+1,fp) != NULL) && (i<MAX_CHAR_FOR_FILE_OPERATION) ) ;
//Ensure array read starts from beginning
i = 0;
while((text[i] != '\0') && (i<MAX_CHAR_FOR_FILE_OPERATION) )
{
printf("%c",text[i++]);
}
fclose(fp);
return 0;
}
int main(int argc, char *argv[])
{
if(argc != 2)
{
printf("Execute the program along with file name to be read and printed. \n\
\rFormat : \"%s <file-name>\"\n",argv[0]);
return -1;
}
char *filename = argv[1];
if( (read_and_show_the_file(filename)) == 0)
{
printf("File Read and Print to stdout is successful\n");
}
return 0;
}