Test the space in a string from a file - c

I am trying to test if the character in a file.txt is a space ' ' or not using this code:
char *Appartient (FILE *f, char *S)
{
int i = 0, nbdechar = 0, nbocc = 0, PosdePremierChar, space = 0;
char c;
while ((c = getc(f)) != EOF) {
PosdePremierChar = ftell(f);
if (c == S[0]) {
nbdechar = 0;
for (i = 1; i < strlen(S); i++) {
c = getc(f);
if (c == S[i]) {
nbdechar++;
}
}
if (nbdechar == strlen(S) - 1) {
nbocc++;
} else {
rewind(f);
fseek(f, PosdePremierChar - 1, SEEK_CUR);
while ((c = getc(f)) != ' ');
}
} else {
while ((c = getc(f)) != ' ') {
space++;
}
}
}
printf("\n Le nb d'occurence est %d", nbocc);
if (nbocc == 0) {
return "false";
} else {
return "true";
}
}
but a weird symbol 'ے' appear like a garbage when I inspect the variable 'c' in my debugger:
What is wrong

Could be the result of converting the end-of-file result from getc(), EOF, (which is standardized to be negative, often -1) to a character.
Note that your loop never terminates if there's no space in the file, since EOF != ' ' and that condition keeps being true after you hit end-of-file for the first time.

Modify your code like this, trace it and you might become enlightened regarding the relation between what getc() returns and how this correlates to chars:
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
int result = EXIT_SUCCESS;
FILE * f = fopen("test.txt", "r");
if (NULL == f)
{
perror("fopen() failed");
result = EXIT_FAILURE;
}
else
{
int result = EOF;
while (EOF != (result = getc(f)))
{
char c = result;
printf("\n%d is 0x%02x is '%c'", result, result, c);
if (' ' == c)
{
printf(" is space ");
}
}
printf("\nread EOF = %d = 0x%x\n", result, result);
fclose(f);
}
return result;
}

You didn't test if f opened, in case it didn't then undefined behavior will happen, check if the file opened
FILE *file;
int chr;
if ((file = fopen("test.txt", "r")) == NULL)
{
fprintf(stderr, "Cannot open `test.txt'\n");
return -1;
}
while (((chr = fgetc(file)) != EOF) && (chr == ' '))
printf("space\n");
You should declare chr of type int, because fgetc() returns an int, as for example EOF requires to be an int and not a char.
Also, debug mode is useful for tracking the values of variables, I bet that it can five you the value in ascii or decimal or hex, as you need if you know how to ask.

Related

How to clear blank lines in files using c?

I am working on a management system project and want to clear the file before adding data to it. I am using this code as a reference. I have rewritten the code from the reference and instead of writing the data from the temporary file(tmp) back to the original(FILE_NAME), I have printed it out to the terminal.
When I compile and run the program, it prints all the content and a few more lines after the end of the file. After this it stops and doesn't finish execution. I have added to comments to help understand my thought process better.
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#define BUFFER_SIZE 1000
#define FILE_NAME "data.csv"
int main()
{
FILE* file;
char buffer[BUFFER_SIZE];
// Opening file
if(file = fopen(FILE_NAME, "r+"))
{
char c; // To get character from buffer
int i = 0; // Index for the buffer character
int isEmpty = 1; // If the line is empty
FILE* tmp;
if(tmp = tmpfile())
{
while(1)
{
buffer[i++] = c;
if(c != '\n') // Checking for blank lines
{
isEmpty = 0;
}
else
{
if(c == '\n' && isEmpty == 0) // Read a word; Print to tmp file
{
buffer[i] = '\0';
fprintf(tmp, "%s", buffer);
i = 0;
isEmpty = 1;
}
else if(c == '\n' && isEmpty == 1) // NOT SURE WHY THIS IS IMPORTANT
{
buffer[i] = '\0';
i = 0;
isEmpty = 1;
}
}
if(c == EOF)
{ break; }
while(1) // Loop to print contents of tmp file onto terminal
{
c = getc(tmp);
printf("c: %c", c);
if(c == EOF)
{ break; }
}
}
}
else
{
printf("Unable to open temporary file\n");
}
fclose(file);
}
else
{
printf("Unable to open file.");
}
getchar();
return 0;
}
UPDATE:
I've modified a few lines and have got it working.
I'd forgotten to assign c in the above program. Also #Barmar won't char c work just as well as int c. Characters can be integers as well right?
Why would large indentations lead to bugs? I find the blocks of code to be more differetiated.
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#define BUFFER_SIZE 1000
#define FILE_NAME "data.csv"
int main()
{
// Variable Declaration
FILE* file;
char buffer[BUFFER_SIZE];
// Opening file
if( file = fopen(FILE_NAME, "r+") )
{
char c; // Reading characters from the file
int i; // Index of the characters
int isEmpty = 1; // 1-> character is empty; 0-> character is not empty
FILE* tmp;
if( tmp = fopen("tmp.csv", "a+") )
{
char c; // Reading characters from files
int i = 0; // Index
int isEmpty = 1; // 1->previous word is empty; 0->previous word is not empty
while( (c = getc(file)) != EOF)
{
if( c != '\n' && c != ' ' && c != '\0' && c != ',')
{
isEmpty = 0;
buffer[i++] = c;
}
else
{
if( c == '\n' && isEmpty == 0 )
{
buffer[i] = '\0';
fprintf(tmp, "%s", buffer);
i = 0;
isEmpty = 1;
}
else if( c == '\n' && isEmpty == 1 )
{
buffer[i] = '\0';
i = 0;
}
}
}
fclose(tmp);
}
else
{
printf("Unable to open temporary file\n");
}
fclose(file);
}
else
{
printf("Unable to open file\n");
}
return 0;
}
Are there are ways to simplify the program and make it more compact or less error prone?

How can I compare user input to string stored into file?

I gotta write a file-handing code which will compare the string received from the user to a string of char stored into a file in C. I've trying since yesterday. I have no clue on how to do that. I tried many things, but nothing seems to work.
//
// 2.c
// IFTM Exercises
//
// Created by Lelre Ferreira on 10/27/19.
// Copyright © 2019 Lelre Ferreira. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, const char * argv[]){
FILE *file = fopen("file.txt", "w");
char text[] = "hi hi hi hi hi hi"; //string to be allocated into the file
char c, userInput[] = "hi"; // simulates the user input
int i = 0, count = 0;
if (file == NULL) {
printf("Failure to create file.\n");
exit(1);
} else {
for (i = 0; i < strlen(text); i++) {
printf("Inserting: [%c]\n", text[i]);
fputc(text[i], file);
}
printf("All done.\n");
}
fclose(file);
fopen("file.txt", "r");
while ((c = fgetc(file) != EOF)){
fscanf(file, "%s", text);
if (strcmp(userInput, text) == 0) {
count++;
}
}
fclose(file);
printf("Many times present: %d\n", count);
return 0;
}
My problem is... the space between every word of the string in the file, because I have to check if there's another word starting, for instance... (Hi Hi)... I thought about using something like this in my code but I did not work as well.
while ((c = fgetc(file) != EOF)){ // While the end of the file does not happen keep running.
if ((c = fgetc(file) != ' ')) { //If an blank space is found... I does not make any sense actually. I'm desesperated.
strcmp(userInput, text){
count++
}
}
}
while ((c = fgetc(file) != EOF)){
if ((c = fgetc(file) != ' ')) {
strcmp(userInput, text){
count++
}
}
}
There are three major problems here.
First, c = fgetc(file) != EOF is the same as c = (fgetc(file) != EOF) which obviously is not what you want. It should be (c = fgetc(file)) != EOF
Second, the above statement has (provided you did not get an EOF) actually read a character. So the if statement should be if(c != ' ')
Third, c needs to be declared as an int

Unexpected behaviour when removing inline comments in C

Stack Overflow! I am on my learning process with the C technology. I have a function which gets an input file, seeks through the file and writes the contents to the output file without the comments.
The function works but it also brakes at some cases.
My Function:
void removeComments(char* input, char* output)
{
FILE* in = fopen(input,"r");
FILE* out = fopen(ouput,"w");
char c;
while((c = fgetc(in)) != EOF)
{
if(c == '/')
{
c = fgetc(in);
if(c == '/')
{
while((c = fgetc(in)) != '\n');
}
else
{
fputc('/', out);
}
}
else
{
fputc(c,out);
}
}
fclose(in);
fclose(out);
}
But when I give a file like this as input:
// Parameters: a, the first integer; b the second integer.
// Returns: the sum.
int add(int a, int b)
{
return a + b; // An inline comment.
}
int sample = sample;
When removing the inline comment it fails to reach the '\n' for some reason and it gives output:
int add(int a, int b)
{
return a + b; }
int sample = sample;
[EDIT]
Thanks for helping me! It works with the case I posted but it brakes in another.
Current code:
FILE* in = fopen(input,"r");
FILE* out = fopen(output,"w");
if (in == NULL) {
printf("cannot read %s\n", input);
return; /* change signature to return 0 ? */
}
if (out == NULL) {
printf("cannot write in %s\n", output);
return; /* change signature to return 0 ? */
}
int c;
int startline = 1;
while((c = fgetc(in)) != EOF)
{
if(c == '/')
{
c = fgetc(in);
if(c == '/')
{
while((c = fgetc(in)) != '\n')
{
if (c == EOF) {
fclose(in);
fclose(out);
return; /* change signature to return 1 ? */
}
}
if (! startline)
fputc('\n', out);
startline = 1;
}
else if (c == EOF)
break;
else {
fputc('/', out);
startline = 0;
}
}
else
{
fputc(c,out);
startline = (c == '\n');
}
}
fclose(in);
fclose(out);
When the file contains division the second variable disappears.
Example:
int divide(int a, int b)
{
return a/b;
}
It gives back:
int divide(int a, int b)
{
return a/;
}
after
while((c = fgetc(in)) != '\n');
you need a fputc('\n', out);
Additional remarks :
In
char c;
while((c = fgetc(in)) != EOF)
c must be an int to manage EOF
Just a typo : ouput must be output to compile
You do not manages well the EOF after you read a '/'
You missed to check the result of the fopen
A proposal :
#include <stdio.h>
void removeComments(char* input, char* output)
{
FILE* in = fopen(input,"r");
FILE* out = fopen(output,"w");
if (in == NULL) {
printf("cannot read %s\n", input);
return; /* change signature to return 0 ? */
}
if (out == NULL) {
printf("cannot write in %s\n", output);
return; /* change signature to return 0 ? */
}
int c;
while((c = fgetc(in)) != EOF)
{
if(c == '/')
{
c = fgetc(in);
if(c == '/')
{
while((c = fgetc(in)) != '\n')
{
if (c == EOF) {
fclose(in);
fclose(out);
return; /* change signature to return 1 ? */
}
}
fputc('\n', out);
}
else if (c == EOF) {
fputc('/', out);
break;
}
else
fputc('/', out);
fputc(c, out);
}
else
{
fputc(c,out);
}
}
fclose(in);
fclose(out);
/* change signature to return 1 ? */
}
int main(int argc, char ** argv)
{
removeComments(argv[1], argv[2]);
}
As Tormund Giantsbane says in a remark it is better to completely remove the line containing only a comment (comment starting on the first column), that new proposal does that :
#include <stdio.h>
void removeComments(char* input, char* output)
{
FILE* in = fopen(input,"r");
FILE* out = fopen(output,"w");
if (in == NULL) {
printf("cannot read %s\n", input);
return; /* change signature to return 0 ? */
}
if (out == NULL) {
printf("cannot write in %s\n", output);
return; /* change signature to return 0 ? */
}
int c;
int startline = 1;
while((c = fgetc(in)) != EOF)
{
if(c == '/')
{
c = fgetc(in);
if(c == '/')
{
while((c = fgetc(in)) != '\n')
{
if (c == EOF) {
fclose(in);
fclose(out);
return; /* change signature to return 1 ? */
}
}
if (! startline)
fputc('\n', out);
startline = 1;
}
else if (c == EOF) {
fputc('/', out);
break;
}
else {
fputc('/', out);
fputc(c, out);
startline = 0;
}
}
else
{
fputc(c,out);
startline = (c == '\n');
}
}
fclose(in);
fclose(out);
/* change signature to return 1 ? */
}
int main(int argc, char ** argv)
{
removeComments(argv[1], argv[2]);
}
Compilation and execution :
pi#raspberrypi:/tmp $ gcc -pedantic -Wextra -g r.c
pi#raspberrypi:/tmp $ cat i
// Parameters: a, the first integer; b the second integer.
// Returns: the sum.
int add(int a, int b)
{
return a + b/c; // An inline comment.
}
int sample = sample;
pi#raspberrypi:/tmp $ ./a.out i o
pi#raspberrypi:/tmp $ cat o
int add(int a, int b)
{
return a + b/c;
}
int sample = sample;
As said by DavidC. in a remark if // is placed in a string the result will not be the expected one, it is also the case in a character even illegal (I mean '//' must not be changed), what about the C comments (/* .. // ... */) etc
When removing the inline comment it fails to reach the '\n' for some reason
Well no, if it failed to reach or see the newline at the end of an inline comment then the program would, presumably, consume the entire rest of the file. What it actually fails to do is write such newlines to the output.
Consider your comment-eating code:
while((c = fgetc(in)) != '\n');
That loop terminates when a newline is read. At that point, the newline, having already been read, is not available to be read from the input again, so your general read / write provisions will not handle it. If you want the such newlines to be preserved, then you need to print them in the comment-handling branch.
Additional notes:
fgetc returns an int, not a char, and you need to handle it as such in order to be able to correctly detect end-of-file.
Your program will go into an infinite loop if the input ends with an inline comment that is not terminated by a newline. Such source is technically non-conforming, but even so, you ought to handle it.

Having trouble reading from text file into a struct array

I recently started at university with C programming (beginner course), and now we are doing our final examination which is about a patients' database.
I'm required to read data from a text file to a struct array (size 10000). The file contains 2 string arrays (personal identification string (10 numbers seperated by a '-') and name string), 1 int array containing photo references and 1 integer containing the amount of photo references per patient. I have tried fscanf but the program just hangs whenever i try to read, when i use fgets, it reads the whole line and stores the integers from the photo reference array into my name array (middle one). I am wondering how I should go about doing this, I've spent days trying to figure out a solution but nothing seems to work. This is what my text file looks like:
123456-1234 Name Name [1, 2, 3, 4]
234567-2345 Name2 Name2 [1, 2]
345678-3456 Name3 Name3 []
And this is my write_to_file function which writes to the file when the program exits:
void write_to_file(Patient reg[], int *pNr_of_patients){
FILE *fp;
fp=fopen("file.txt","w");
if(*pNr_of_patients>0){
int i,j;
for(i=0;i<*pNr_of_patients;i++){
fprintf(fp,"%s\t%s\t[",reg[i].pers_nr,reg[i].name);
for(j=0;j<reg[i].nr_of_ref-1;j++){
fprintf(fp,"%d, ",reg[i].photo_ref[j]);
}
if(reg[i].photo_ref[j]==0){
fprintf(fp,"]");
}else{
fprintf(fp,"%d]",reg[i].photo_ref[j]);
}
fprintf(fp,"\n");
}
fclose(fp);
}
}
This is my read_from_file function, it's missing code for reading the int array values at the end:
Edit: I added a for loop to remove the characters starting at "[" from the name string, now i just need to know how to read the array values at the end into the struct's photo reference array.
void read_from_file(Patient reg[],int *pNr_of_patients){
FILE *fp;
fp=fopen("file.txt","r");
if(fp!=NULL){
reg[*pNr_of_patients].nr_of_ref=0;
int i=0, pos;
while(fgets(reg[*pNr_of_patients].pers_nr,13,fp)!=NULL){
reg[*pNr_of_patients].pers_nr[strlen(reg[*pNr_of_patients].pers_nr)-1]='\0';
fgets(reg[*pNr_of_patients].name,31,fp);
reg[*pNr_of_patients].name[strlen(reg[*pNr_of_patients].name)-1]='\0';
for(pos=0;pos<30;pos++){
if(reg[*pNr_of_patients].name[pos]=='['){
reg[*pNr_of_patients].name[pos]='\0';
}
}
(*pNr_of_patients)++;
}
fclose(fp);
}else{
printf("File does not exist\n");
}
}
This is what my Patient struct looks like:
struct patient{
char pers_nr[12], name[30];
int photo_ref[10], nr_of_ref;
};
typedef struct patient Patient;
Calling read_from_file in main:
int main(void){
Patient patient_register[10000];
int nr_of_patients=0;
read_from_file(patient_register,&nr_of_patients);
database_management(patient_register,&nr_of_patients); //this is where I fill all the data into the array before writing to the file at the end
write_to_file(patient_register,&nr_of_patients);
return 0;
}
I think that scanning input is one of the hardest in C. That's why libraries like cs50 exists, to ease up reading input for new C users. Anyway, I constructed my solution, but I redesigned your function.
The first solution reads a single Patient from a line. It does not use sscanf the only standard call that set's errno is to strtol, which is used to convert up numbers.
The second function uses sscanf and some crazy format string construction to stay safe of buffer overflow.
It all brings down at to how the input stream is constructed and how much you trust it.
#include <stdio.h>
#include <assert.h>
#include <stddef.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <limits.h>
struct patient{
char pers_nr[12];
char name[30];
int photo_ref[10];
size_t nr_of_ref;
};
typedef struct patient Patient;
int patient_read_from_line_1(const char line[], Patient *p)
{
assert(line != NULL);
assert(p != NULL);
// check the first 12 characters ----------
// first 6 chars must be numbers
for (int i = 0; i < 6; ++i) {
if (!isdigit(line[i])) {
return -__LINE__;
}
}
// followed by a single '-'
if (line[6] != '-') {
return -__LINE__;
}
// followed by 4 numbers
for (int i = 7; i < 7 + 4; ++i) {
if (!isdigit(line[i])) {
return -__LINE__;
}
}
// followed by a space
if (line[7 + 4] != ' ') {
return -__LINE__;
}
// read up first field ---------------------
// cool first field checks out
memcpy(p->pers_nr, line, 11);
p->pers_nr[11] = '\0';
line += 12;
// let's omit spaces
while (line[0] == ' ') {
line++;
}
// read up second field --------------------------
// now we should read a two strings separated by a space
// so we should read up until a second space
if (!isalpha(*line)) {
return -__LINE__;
}
const char *pnt_first_space = strchr(line, ' ');
if (pnt_first_space == NULL) {
return -__LINE__;
}
const char *pnt_another_space = strchr(pnt_first_space + 1, ' ');
if (pnt_another_space == NULL) {
return -__LINE__;
}
const size_t name_to_read_length = pnt_another_space - line;
if (name_to_read_length > sizeof(p->name)) {
return -__LINE__;
}
memcpy(p->name, line, name_to_read_length);
p->name[name_to_read_length] = '\0';
// buh two fields done, now the array
line += name_to_read_length;
// let's omit the spaces
while (line[0] == ' ') {
line++;
}
// read up array -----------------------------------
// array
if (line[0] != '[') {
return -__LINE__;
}
line++;
for (size_t numscnt = 0;; ++numscnt) {
if (numscnt >= sizeof(p->photo_ref)/sizeof(*p->photo_ref)) {
return -__LINE__;
}
char *pnt;
errno = 0;
long num = strtol(line, &pnt, 10);
if (errno) {
return -__LINE__;
}
if (!(INT_MIN < num && num < INT_MAX)) {
return -__LINE__;
}
p->photo_ref[numscnt] = num;
line = pnt;
// omit spaces
while (*line == ' ') line++;
// now we should get a comma
if (line[0] != ',') {
// if don't get a comma, we need to get a ]
if (line[0] == ']') {
// cool
++line;
// but remember to save the count
p->nr_of_ref = numscnt + 1;
// cool
break;
}
return -__LINE__;
}
++line;
// omit spaces
while (*line == ' ') line++;
// start again
}
// this needs to be end of line or newline
if (line[0] != '\0' && line[0] != '\n') {
return -__LINE__;
}
// success!
return 0;
}
// ok, ok, ok, let's use sscanf
int patient_read_from_line_2(const char line[], Patient *p)
{
assert(line != NULL);
assert(p != NULL);
int ret;
int pos;
// read up first fiedl and half of the second ------------------
ret = sscanf(line, "%12s %30[^ ] %n", p->pers_nr, p->name, &pos);
if (ret != 2) {
return -__LINE__;
}
line += pos;
// read up another half of the second field -------------------
const size_t cur_name_len = strlen(p->name);
p->name[cur_name_len] = ' ';
char tmp[20];
ret = snprintf(tmp, 20, "%%%d[^ ] [%%n", (int)(sizeof(p->name) - cur_name_len - 1));
if (ret < 0) {
return -__LINE__;
}
ret = sscanf(line, tmp, &p->name[cur_name_len + 1], &pos);
if (ret != 1) {
return -__LINE__;
}
line += pos;
// read up array *sigh* -------------------------------------------
for (p->nr_of_ref = 0;; ++p->nr_of_ref) {
if (p->nr_of_ref >= sizeof(p->photo_ref)/sizeof(*p->photo_ref)) {
return -__LINE__;
}
ret = sscanf(line, " %d%1s%n", &p->photo_ref[p->nr_of_ref], tmp, &pos);
if (ret == 0) {
// hm...
if (line[0] == ']') {
// ach all ok, empty numbers list;
line++;
p->nr_of_ref++;
break;
}
return -__LINE__;
}
if (ret != 2) {
return -__LINE__;
}
line += pos;
if (tmp[0] != ',') {
if (tmp[0] == ']') {
// whoa! success
p->nr_of_ref++;
// cool
break;
}
return -__LINE__;
}
}
// so what's left? - EOF or newline
if (line[0] != '\0' && line[0] != '\n') {
return -__LINE__;
}
// success!
return 0;
}
long patient_read_from_file(FILE *fp, Patient patients[], size_t patients_len)
{
size_t patients_cnt = 0;
char line[256];
// for each line in file
while (fgets(line, sizeof(line), fp) != NULL) {
const int ret = patient_read_from_line_2(line, &patients[patients_cnt]);
if (ret < 0) {
// hanle reading error
return ret;
}
patients_cnt++;
if (patients_cnt > patients_len) {
// no more memory in patients left
return -__LINE__;
}
}
return patients_cnt;
}
void patient_fprintln(FILE *f, const Patient *p)
{
fprintf(f, "%s %s [", p->pers_nr, p->name);
for (size_t i = 0; i < p->nr_of_ref; ++i) {
fprintf(f, "%d", p->photo_ref[i]);
if (i + 1 != p->nr_of_ref) {
fprintf(f, ",");
}
}
fprintf(f, "]\n");
}
int main()
{
FILE *fp;
fp = stdin; // fopen("file.txt","r");
if (fp == NULL) {
return -__LINE__;
}
Patient patients[3];
const long patients_cnt = patient_read_from_file(fp, patients, sizeof(patients)/sizeof(*patients));
if (patients_cnt < 0) {
fprintf(stderr, "patient_read_from_file error %ld\n", patients_cnt);
return patients_cnt;
}
fclose(fp);
printf("Readed %d patients:\n", patients_cnt);
for (size_t i = 0; i < patients_cnt; ++i) {
patient_fprintln(stdout, &patients[i]);
}
return 0;
}
Live version available at onlinedbg.
This can be simplified for 100%. This has bugs for 100%. It is just to show what methods (strtol, memcpy, sscanf, isdigit, isalpha) are sometimes used by people to read from input. Also I specify length modifier to scanf (sscanf(..., "%12s") to handle overflows (hopefully). Try to always check return values from scanf and other standard functions (maybe checking snprintf return value is a little too much, but hey, let's be consistent). Be vary, that on some platforms the %n scanf modifier happens not to work. Also this can be build up to use dynamic allocation using malloc, realloc and free, both on line reading (basically it is equal to writing custom version of GNU getline), reading strings from input, reading int's array from input and dynamic allocations of patients.
This was meant as a comment but got too long, so I type it here.
read_from_file() appears overly complex. You might consider revisiting fscanf, reading the photo references as a whole string and then parsing into integers which you can assign to the photo_ref array. (While the code below might compile, I haven't verified that it works. It's just an idea of how one might proceed.)
void read_from_file (Patient reg[], int *pNr_of_patients)
{
FILE *fp;
fp = fopen ("file.txt", "r");
if (fp != NULL)
{
int n;
int i = 0; // position in photo_ref
char refs[30];
*pNr_of_patients = 0;
while (EOF !=
(n =
fscanf (fp, "%s %[^[]%[^]]]", reg[*pNr_of_patients].pers_nr,
reg[*pNr_of_patients].name, refs)))
{
// btw, reg[*pNr_of_patients].name may contain terminating blanks. right trim it. that's easy enough.
if (n > 2)
{ /* found photo refs.Now split the string into integers */
char *s = refs + 1; //skip '['
char *p;
while (*s && i<10){ // scan for the integers, 10 of them
while (*s && *s == ' ')
s++; // skip blanks
p = s; // mark start of number
while (*p && *p != ',')
p++;
if (*p == ',')
*p = 0;
reg[*pNr_of_patients].photo_ref[i++] = atoi (s); //tip: use strtol(3), verify that `i' isnt larger than size of the array
s = p + 1; // skip ','. Must Do: verify that `s' hasnt yet moved past the end of `ref'!!
}
}
(*pNr_of_patients)++;
}
fclose (fp);
}
else
{
printf ("File does not exist\n");
}
}
There are some good answers already, but most of them try to use a single method to parse all elements of the line. I would read whole lines into a buffer first, then use sscanf() to parse the patient number and name, but use strtok() to split the array into its individual components:
void read_from_file(Patient reg[], int *pNr_of_patients) {
FILE *fp = fopen("file.txt", "r");
if (!fp) {
fprintf(stderr, "Error opening file: %s\n", strerror(errno));
*pNr_of_patients = 0;
return;
}
char line[1024];
int i = 0;
while (fgets(line, sizeof line, fp)) {
int offset = 0;
int refs = 0;
sscanf(line, "%11s %29[^[] [%n", &reg[i].pers_nr, &reg[i].name, &offset);
for (char *tok = strtok(line + offset, ","); tok && refs < 10; tok = strtok(NULL, ",")) {
if (*tok != ']')
reg[i].photo_ref[refs++] = atoi(tok);
}
reg[i].nr_of_ref = refs;
i++;
}
*pNr_of_patients = i;
}
Divide and Conquer
Break this down into steps. Make a function that populates 1 Patient.
The below is untested code. Consider it a starting point. The deign goal is to make a function that reads 1 line into 1 Patient.
Read in 1 entire line
// return 1: success, 0: failure EOF:end-of-file
int read_once_from_file(FILE *stream, Patient *pat_ptr) {
Patient pat = { 0 };
char buffer[100 + 30*13];
if (fgets(buffer, sizeof buffer, stream) == NULL) {
return EOF;
}
Parse the first part. Use "%n" which records the parsing offset. Use width limits on string input.
int n = 0;
if (sscanf(buffer, " %11[^\t] %29[^\t] [ %n", pat.pers_nr, pat.name) != 2) {
return 0; // improper formatted input
}
char *p = buffer + n;
Now look for ']' and photo_ref
if (*p != ']') {
for (pat.nr_of_ref=0; ; pat.nr_of_ref++) {
if (sscanf(p, "%d %n", &pat.photo_ref[i], &n) != 1) {
return 0; // improper formatted input
}
p += n;
if (*p == ']') {
pat.nr_of_ref++;
break;
}
if (*p != ',' || pat.nr_of_ref + 1 == 10) {
return 0; // improper formatted input
}
p++;
}
}
Save result
*pat_ptr = pat;
return 1;
}
Call read_once_from_file() as needed
void read_from_file(Patient reg[],int *pNr_of_patients){
*pNr_of_patients = 0;
FILE *fp = fopen("file.txt","r");
if(fp){
for (int i = 0; i<10000; i++) {
int count = read_once_from_file(fp, &reg[i]);
if (count == EOF) {
break;
}
if (count != 1) {
// error
fprintf(stderr, "Input error\n");
break;
}
}
*pNr_of_patients = i;
fclose(fp);
}
}

Word Searching using fgetc

I am trying to make word search using fgetc. I understand what fgetc does but i am getting seg fault. on running the gdb test, i returns the following. Is there an easier way to implement the search function?? i am new to programming.
thank you for the help.
#0 0x00007ffff7aa4c64 in getc () from /lib64/libc.so.6
#1 0x000000000040070c in main ()
Where am i going wrong?
#include <stdio.h>
#include <stdlib.h>
int isAlpha(char c)
{
if( c >= 'A' && c <='Z' || c >= 'a' && c <='z' || c >= '0' && c <= '9' )
{
return 1;
}
else
{
return 0;
}
}
int CheckFunctionn(int length, int message_counter, char ref_word[], char newmessage[])
{
int newCounter = 0;
int counterSuccess = 0;
while(newCounter < length)
{
if(ref_word[newCounter] == newmessage[newCounter + message_counter])
{
counterSuccess++;
}
newCounter++;
}
if(counterSuccess == length)
{
return 1;
}
else
{
return 0;
}
}
int main(int argc, char *argv[])
{
char message[300];
int counter = 0;
int ref_length = 0;
int alphaCounter = 0;
int alphaCounterTime = 0;
int messageCounter = 0;
int word_counter = 0;
FILE* input;
FILE* output;
//long fileLength;
//int bufferLength;
//char readFile;
//int forkValue;
input = fopen(argv[2],"r");
output = fopen(argv[3],"w");
int c;
c = fgetc(input);
while(c != EOF)
{
while((argv[1])[ref_length] !='\0')
{
// if string is "HEY", (argv[1]) is HEY, ref_counter is the length
// which in this case will be 3.
ref_length++; //<-- takes care of the length.
}
while(alphaCounter < ref_length)
{
// this will add to alphaCounter everyetime alphaCT is success.
alphaCounterTime += isAlpha((argv[1])[alphaCounter]);
alphaCounter++;
}
if(alphaCounterTime != ref_length)
{
return 0;
}
if((messageCounter == 0 ) && (message[messageCounter + ref_length] == ' ' || message[messageCounter] == '\n' || message[messageCounter]== '\t')) // counts the whole things and brings me to space
{
// compare the message with the word
word_counter += CheckFunctionn(ref_length, messageCounter, argv[1], message);
}
if((message[messageCounter] == ' ' || message[messageCounter] == '\n' || message[messageCounter]== '\t') && (message[messageCounter + ref_length + 1] == ' ' || message[messageCounter + ref_length + 1] == '\n' || message[messageCounter + ref_length + 1]== '\t'))
{
word_counter += CheckFunctionn(ref_length, messageCounter + 1, argv[1], message);
}
if((message[messageCounter]== ' '|| message[messageCounter] == '\n' || message[messageCounter]== '\t') && (messageCounter + ref_length+1)== counter) //<-- this means the length of the message is same
{
word_counter += CheckFunctionn(ref_length, messageCounter + 1, argv[1], message);
}
messageCounter++;
}
fclose(input);
fclose(output);
return 0;
}
You're almost certainly failing to open the input file. If fopen fails, it returns NULL, and calling fgetc(NULL) has undefined behavior, and a segmentation fault is one possible outcome of undefined behavior.
You need to check for errors and handle then accordingly. You also need to check if your program was given sufficient arguments. Here's one way to handle them:
if (argc < 3)
{
fprintf(stderr, "Usage: %s input-file output-file\n", argv[0]);
exit(1);
}
input = fopen(argv[1],"r");
if (input == NULL)
{
fprintf(stderr, "Error opening input file %s: %s\n", argv[1], strerror(errno));
exit(1);
}
output = fopen(argv[2],"w");
if (output == NULL)
{
fprintf(stderr, "Error opening output file %s: %s\n", argv[2], strerror(errno));
exit(1);
}
You only read one character into c, then loop while(c != EOF) which is almost always an infinite loop. Inside that loop, you increment messageCounter which you use to walk past the end of an array -- boom!
Per your comment, argc is 2, but you refer to argv[2] which would be the third element of the args, and will be NULL. The FILE * is going to end up being NULL too (because it's invalid to pass NULL to fopen).
It will be very easy if you use strcmp function in this...
What you have to do is first find the length of ur file using ftell and after that allocate that much memory then fill that memory using fgetc or fgets or any other file function...then just use strcmp function on that....bingo!!!!! :)

Resources