Selectively reading string part of a file using C - c

I have a .txt file with strings each line and a number assigned to each string and a - in between the string and the number.
Now I want to read only the string part not the number or the - in between, store them in an array and write only the strings in another file.
I used the following approach:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 100
struct String {
long long int num;
char name[50];
char C;
} S[MAX], temp;
void file_write(int n, struct String S[]) {
FILE *pp;
pp = fopen("std3.txt", "a"); //second file where I want to write only string part.
for (int i = 0; i < n; i++) {
fprintf(pp, "%s", S[i].name); //storing the strings in another file
fputs("\n", pp);
}
fclose(pp);
}
int main() {
int n;
FILE *fp;
fp = fopen("str.txt", "r");
printf("Enter the number of strings : ");
scanf("%d", &n);
for (int i = 0; i < n; i++) {
fscanf(fp, " %[^\n]", S[i].name);
fscanf(fp, "%lld", &S[i].num);
fscanf(fp, "%c", &S[i].C);
}
file_write(n, S);
fclose(fp);
return 0;
}
But I'm getting an undesirable output:

Here is a simple solution using fscanf() and the * assignment suppression option:
#include <stdio.h>
int main() {
int n = 0;
FILE *fp = fopen("str.txt", "r");
// second file where I want to write only string part.
FILE *pp = fopen("std3.txt", "a");
if (fp == NULL || pp == NULL) {
fprintf(stderr, "cannot open files\n");
return 1;
}
printf("Enter the number of strings: ");
scanf("%d", &n);
for (int i = 0; i < n; i++) {
char name[50];
int c;
if (fscanf(fp, "%*d - %49[^\n]", name) == 1) {
fprintf(pp, "%s\n", name);
/* flush any extra characters and the newline if present */
while ((c = getc(fp)) != EOF && c != '\n')
continue;
} else {
break;
}
}
fclose(fp);
fclose(pp);
return 0;
}

Scanf (and its variations) is a very powerful function... I think the following line is what you want.
for(int i=0;i<n;i++)
{
fscanf(fp, "%*[^A-Z]%[^\n]", S[i].name);
}
A brief description of what it does is: It discards any character that is not a capital letter then reads everything from the first capital letter until the end of line.
If the names are allowed to start with lowercase, you can change it to:
fscanf(fp, "%*[^A-Za-z]%[^\n]", S[i].name);

Related

Output Text from File in Reverse Order in C

I was trying to make a code on C, which reads the file.txt, outputs it into console, and then counts rows, words etc, and after all is exporting the content of file.txt to file2.txt but in reverse order.
The text need to go from this:
I
Love
You
to this:
ouY
evoL
I
What I have in my text.file:
enter image description here
What i get with my code now:
enter image description here
Here is my code that's need improvement, because it prints the code how i need but with blank rows, which is not needed. And it needs to be exporting into another file also:
fseek(fptr,0,SEEK_END);
pos=ftell(fptr);
i=0;
while(i<pos)
{
i++;
fseek(fptr,-i,SEEK_END);
ch=fgetc(fptr);
printf("%c",ch);
}
there's full code:
#include <stdio.h>
int main ()
{
FILE *fptr;
int i, n, j, pos;
char str[100];
char fname[20]="mfile.txt";
char newch[500];
int wrd=1,charctr=1,rows=1;
char str1;
char ch;
int no_lines = 1;
int COUNT = 0;
fptr = fopen(fname,"r");
if(fptr == NULL)
{
printf(" \n");
printf("File does not exist or can not be opened.");
}
else
{
ch=fgetc(fptr);
printf(" \n");
printf("The content of the file %s are: \n", fname);
printf(" \n");
while(ch != EOF)
{
printf("%c",ch);
if(ch==' '||ch=='\n')
{
wrd++;
}
else
{
charctr++;
}
if(ch=='\n')
{
rows++;
}
ch=fgetc(fptr);
}
int wrd1 = wrd - 1;
float charctr1 = charctr - 1;
float rows1 = rows;
float averageSymbol = charctr1 / rows1;
printf(" \n");
printf("\nwrd = %d, charctr = %d", wrd, charctr-1);
printf("\nThe number of rows in the file %s are : %d\n", fname,rows);
printf("\nThe average amount of symbols in a row is %f\n", averageSymbol);
printf(" \n");
}
fseek(fptr,0,SEEK_END);
pos=ftell(fptr);
i=0;
while(i<pos)
{
i++;
fseek(fptr,-i,SEEK_END);
ch=fgetc(fptr);
printf("%c",ch);
}
fclose(fptr);
return 0;
}
Ok so if I understand correctly you want to get rid of some of the empty lines which show up in your code and then you want to also write the output of the program (the reversed text) into another file? I am assuming that you want the sentences to be also in the original order.
#include <stdio.h>
int main ()
{
FILE *fptr;
FILE *fptr2;
int i, n, j, pos;
char str[100];
char fname[20]="mfile.txt";
char fname2[20]="outputfile.txt";
char newch[500];
int wrd=1,charctr=1,rows=1;
char str1;
char ch;
int no_lines = 1;
int COUNT = 0;
fptr2 = fopen(fname2, "w+");
fptr = fopen(fname,"r");
if(fptr == NULL)
{
printf(" \n");
printf("File does not exist or can not be opened.");
}
else
{
ch=fgetc(fptr);
printf("The content of the file %s are: \n", fname);
while(ch != EOF)
{
printf("%c",ch);
if(ch==' '||ch=='\n')
{
wrd++;
}
else
{
charctr++;
}
if(ch=='\n')
{
rows++;
}
ch=fgetc(fptr);
}
int wrd1 = wrd - 1;
float charctr1 = charctr - 1;
float rows1 = rows;
float averageSymbol = charctr1 / rows1;
printf("\nwrd = %d, charctr = %d", wrd, charctr-1);
printf("\nThe number of rows in the file %s are : %d\n", fname,rows);
printf("The average amount of symbols in a row is %f\n", averageSymbol);
}
fseek(fptr,0,SEEK_END);
pos=ftell(fptr);
i=0;
while(i<pos)
{
i++;
fseek(fptr,-i,SEEK_END);
ch=fgetc(fptr);
printf("%c",ch);
fputc(ch,fptr2);
}
fclose(fptr);
fclose(fptr2);
return 0;
}
This version first checks if a file called outputfile.txt exists and if no, it creates it. If said file already exists then the program overwrites the stuff which was originally in the file with the new program output (it doesn't clear the file all the way).

increment variable doubles at the end of my program

So I have this program where it asks the user for a filename to read, and a filename to save the output to. This program basically counts the frequency of a letter inside the txt file. Here is the program...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(void)
{
char letter[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ", FileName[50], SaveFile[50], print[256], stry[50], scount[50], point;
int i, j, count = 0;
FILE * readFile, *saveFile;
printf("Enter a file to read: ");
gets(FileName);
printf("Enter a filename to save results: ");
gets(SaveFile);
printf("Letter Frequency\n\n");
saveFile = fopen(SaveFile, "wb");
for(i = 0; i <= strlen(letter)-1; i++)
{
readFile = fopen(FileName, "r");
while(!feof(readFile))
{
fgets(print, 256, readFile);
for(j = 0; j <= strlen(print); j++)
{
if(toupper(print[j]) == toupper(letter[i]))
{
count++;
}
}
point = letter[i];
stry[0] = point;
sprintf(scount, "%d", count);
if(feof(readFile) && count > 0)
{
printf("%s %d\n", stry, count);
fprintf(saveFile, stry);
fprintf(saveFile, " ");
fprintf(saveFile, scount);
fprintf(saveFile, "\n");
}
}
count = 0;
}
fclose(readFile);
return 0;
}
I input a txt file named readme.txt that I modified. It contains
aaa
bbb
ccc
ddd
But when I run it, and used readme.txt to be read, the output is
A 3
B 3
C 3
D 6
The frequency of letter D must be only 3. I further modified the content of the readme.txt file, and figured out that value of the variable count is doubled when reading the last line. For example, the content of the txt file is
hello mama
hihihi
maria maria
woohoo
the output will be
A 6
E 1
H 6
I 5
L 2
M 4
O 9
R 2
W 2
I read my program so many times already, and I still can't find my wrong doings. I hope you can help me fix this problem. Your help will be very much appreciated!
EDIT:
This is what my code looks like after making the changes that were recommended in the comments section:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(void)
{
char letter[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ", FileName[50], SaveFile[50], print[256], stry[50], scount[50], point;
int i, j, count = 0;
FILE * readFile, *saveFile;
printf("Enter a file to read: ");
gets(FileName);
printf("Enter a filename to save results: ");
gets(SaveFile);
printf("Letter Frequency\n\n");
saveFile = fopen(SaveFile, "wb");
for(i = 0; i < strlen(letter); i++){
readFile = fopen(FileName, "r");
while(fgets(print, 256, readFile) != NULL)
{
fgets(print, 256, readFile);
for(j = 0; j <= strlen(print); j++)
{
if(toupper(print[j]) == toupper(letter[i]))
{
count++;
}
}
point = letter[i];
stry[0] = point;
sprintf(scount, "%d", count);
if(feof(readFile) && count > 0)
{
printf("%s %d\n", stry, count);
fprintf(saveFile, stry);
fprintf(saveFile, " ");
fprintf(saveFile, scount);
fprintf(saveFile, "\n");
}
}
count = 0;
}
fclose(readFile);
return 0;
}

C Problems with fscanf

Thanks for all the answers, after the corrections the code did not work for a stupid error ... I opened both files with the same file pointer "database" ...
I've read dozens of questions like this but I can't get out of it, I'm going crazy.
The exercise that I have to do asks me to organize the items of a list in a file .txt that has elements of the type: Name Surname Age Wage, in alphabetical order according to the surname.
I have already created a function to insert the elements into the file and it works well.
I then went to the function to organize them but the process stops after the fscanf, and putting some test printf I saw that no values are assigned to the strings or that are assigned absurd numbers.
Please help ... thanks.
This is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX 64
#define MAXFILE 100
void insert();
int fullcheck();
void sort();
typedef struct {
char name[MAX];
char surname[MAX];
int age;
double wage;
} data;
int main() {
insert();
return EXIT_SUCCESS;
}
void insert() {
char c;
int i;
data tmp;
FILE* database;
if ((fullcheck())>MAXFILE-1)
printf("Errore: database pieno.\n");
else {
database=fopen("database.txt", "a");
printf("Nome: ");
fgets(tmp.name, MAX, stdin);
tmp.name[strlen(tmp.name)-1]='\0';
printf("Cognome: ");
fgets(tmp.surname, MAX, stdin);
tmp.surname[strlen(tmp.surname)-1]='\0';
for (i=0; i<strlen(tmp.surname); i++) {
if (tmp.surname[i]==' ')
tmp.surname[i]='#';
}
printf("Eta': ");
scanf("%d", &tmp.age);
printf("Salario: ");
scanf("%lf", &tmp.wage);
while((c=getchar())!='\n');
fprintf(database, "%s %s %d %.0lf \n", tmp.name, tmp.surname, tmp.age, tmp.wage);
fflush(database); fclose(database);
if ((fullcheck())>1)
sort();
}
}
int fullcheck() {
char c;
int r=0;
FILE* database;
if ((database=fopen("database.txt", "r"))==NULL) {
return 0;
}
else {
while((c=getc(database))!=EOF) {
if(c=='\n')
r++;
}
return r;
}
}
void sort() {
char tmpstr[MAX];
int len=fullcheck(), i, a, b;
data tmp[len];
FILE* database;
FILE* sorted;
database=fopen("database.txt", "r");
database=fopen("sorted.txt", "w");
for (i=0; i<=len; i++) {
fscanf(database, "%s %s %d %lf \n", &tmp[i].name, &tmp[i].surname, &tmp[i].age, &tmp[i].wage);
}
for (a=0 ; a<(len-1); a++) {
for (b=0; b<(len-1); b++) {
if ((tolower(tmp[b].surname[0]))>(tolower(tmp[b+1].surname[0]))) {
strcpy(tmpstr, tmp[b].surname);
strcpy(tmp[b].surname, tmp[b+1].surname);
strcpy(tmp[b+1].surname, tmpstr);
}
}
}
for (a=0; a<(len-1); a++) {
fprintf(sorted, "%s %s %d %.0lf \n", tmp[a].name, tmp[a].surname, tmp[a].age, tmp[a].wage);
}
fflush(database); fclose(database); remove("database.txt");
fflush(sorted); fclose(sorted); rename("sorted.txt", "database.txt");
}
Off by 1
Code attempts to read into len+1 elements of tmp[].
data tmp[len];
for (i=0; i<=len; i++) { // too many
fscanf(database, "%s %s %d %lf \n", &tmp[i].name, &tmp[i].surname, &tmp[i].age, &tmp[i].wage);
}
I saw that no values are assigned to the strings (OP)
Better code would use width limits and test fscanf() result before using the data scanned.
// v---- < not <=
for (i=0; i<len; i++) {
if (fscanf(database, "%63s %63s %d %lf",
&tmp[i].name, &tmp[i].surname, &tmp[i].age, &tmp[i].wage) != 4) {
// ^^^^ test!
break;
}
Even better code would read a line with fgets() into a stirng and then attempt to parse the string.
Off by 2
Code's attempt to find number of lines can be short by 1 if the last line does not end with a '\n'.
Alternative
size_t fullcheck(void) {
FILE* database = fopen("database.txt", "r");
if (database == NULL) {
return 0;
}
int previous = '\n';
int c;
size_t r=0;
while((c=getc(database))!=EOF) {
if (previous == '\n') r++;
previous = c;
}
fclose(database);
return r;
}
Missing fclose()
fullcheck() doesn't close the file after opening it.
int
Use an int to distinguish the typically 257 different returns values of fgetc(). Note when char` is unsinged, OP's code is an infinite loop.
More woes
The loop to print the sorted list is off-by-one, too short. And the sorting itself only looks at the first letter of each name, should use strcmp.
#user3386109
Maybe more?
Make sure to close the file here, before every return:
int fullcheck() {
char c;
int r=0;
FILE* database;
if ((database=fopen("database.txt", "r"))==NULL) {
fclose(database);
return 0;
}
else {
while((c=getc(database))!=EOF) {
if(c=='\n')
r++;
}
fclose(database);
return r;
}
}
And also a little bit fixing in the loop_counters here:
void sort() {
char tmpstr[MAX];
int len=fullcheck(), i, a, b;
data tmp[len];
FILE* database;
FILE* sorted;
database=fopen("database.txt", "r");
sorted=fopen("sorted.txt", "w+");
for (i=0; i<len; i++) {
fscanf(database, "%s %s %d %lf \n", &tmp[i].name, &tmp[i].surname, &tmp[i].age, &tmp[i].wage);
printf("%s", tmp[b+1].surname);
system("pause");
}
for (a=0 ; a<(len); a++) {
for (b=0; b<(len); b++) {
if ((tolower(tmp[b].surname[0]))>(tolower(tmp[b+1].surname[0]))) {
strcpy(tmpstr, tmp[b].surname);
strcpy(tmp[b].surname, tmp[b+1].surname);
strcpy(tmp[b+1].surname, tmpstr);
printf("%s", tmp[b+1].surname);
system("pause");
}
}
}
for (a=0; a<(len); a++) {
fprintf(sorted, "%s %s %d %.0lf \n", tmp[a].name, tmp[a].surname, tmp[a].age, tmp[a].wage);
}
fclose(sorted);
fclose(database);
}

fscanf not reading from a file containing asterisk characters

I tried to read a file containing an empty box of '*', the error message doesn't get printed, so the file is opened, but the scan doesn't work. I tried to print the count variable, and the value of count is 0. I don't really know where the fault is. Please help... Thanks
the file content that I want to read
int openmap(int file_no){
char filename[32];
char mapp[100][100];
int number;
int count;
int x[100];
int nomor = 1;
for(int i = 1; i <= file_no; i++){
sprintf(filename, "map%d.txt", i);
FILE *test = fopen(filename,"r");
if(test)
{
printf("%2d. Map %d\n", nomor, i);
x[nomor-1] = i;
nomor++;
fclose(test);
}else if(!test && i > file_no){
printf("No map available!");
return 1;
}
}
do{
printf("[0 to cancel] [1 - %d]>> ", nomor-1);
scanf("%d", &number);
}while(number < 0 || number > file_no);
if(number > 0){
sprintf(filename,"map%d.txt", x[number-1]);
printf("%s", filename);
FILE *open = fopen(filename, "r");
if(!open){
printf("error");
}
while(!feof){
fscanf(open, "%[^\n]\n", mapp[count]);
count++;
}
fclose(open);
for(int i = 0; i < count ; i++){
printf("%s\n", mapp[i]);
}
}
}
I created a small test program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main () {
char mapp[100][100];
int i, count = 0;
char filename[32];
sprintf(filename, "test.txt");
FILE *open = fopen(filename, "r");
if(!open){
printf("error");
}
while(!feof(open)){
fscanf(open, "%[^\n]\n", mapp[count]);
count++;
}
fclose(open);
for(i = 0; i < count ; i++){
printf("%s\n", mapp[i]);
}
}
as far as i can see the only issue you have regarding the relevant section is your while loop condition, you should use: while(!feof(open)) - i tested my solution and it works so it seems that this is the only issue in your solution

dealing with string input in C

I am trying to input string into fixed size char array.
I have a questions:
when I input a string which is bigger than the char array, the array become bigger without any additional declaration. I want to make the code only take the string that 'equal or smaller than the char array'.
Thank You.
CODE:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
/***************************Function****************************/
int string_length(char s[]) {
int c = 0;
while (s[c] != '\0')
c++;
return c;
}
/**************************************************************/
char *str;
int arrSize;
void opt1()
{
printf("Enter array size: ");
scanf("%d", &arrSize);
arrSize=arrSize+1;
str = malloc(arrSize);
return;
}
void opt2()
{
printf("Enter characters: ");
scanf("%s", str);
length = string_length(str);
printf("your input is '%s'\n", str);
printf("your input length is '%d'\n", length);
return;
}
int main()
{
int input = 0;
while(input != 3) {
printf("\n NAME \n");
printf("\n");
printf("--------------------------------------\n");
printf("1) Making Array \n");
printf("2) Check Array \n");
printf("3) Quit\n");
printf("\nEnter selection: ");
scanf("%d", &input);
if( input == 1 ) {
/* */
opt1();
}
else if(input == 2) {
opt2();
}
}
return 1;
}
OP wants to read data, yet if larger that the target array, then do not change the target array.
// 1: success
// -1 EOF
// 0: Input too long
int read_array(char *buffer, size_t size) {
char tmp[size];
size_t i = 0;
int ch;
while ((ch = fgetc(stdin)) != EOF && ch != '\n') {
if (i < size) {
tmp[i++] = ch;
}
}
if (ch == EOF && i == 0) return EOF;
if (i >= size) return 0; // too many
memcpy(buffer, tmp, i);
buffer[i] = '\0';
return 1;
}
Normally code could use fgets(), but there are corner cases that fail to meet OP goals.
To read in a whole line, you can use fgets:
char line[80];
if (fgets(line, sizeof line, stdin) != NULL) {
// use the input
}
Now you won't need to check if the user entered more than the limit, since fgets will only get the first 79 (-1 for null terminator) characters; the remainder, if any, will be ignored.

Resources