I have problem with getNumber function, because my output_file contains zeros. And in my opinion it should not. I want my program to print all numbers and then add them up.
Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define CHUNK 12
char *getNumber(FILE *infile);
int main(int argc, char *argv[])
{
char *number, *pEnd;
FILE *infile, *outfile;
int newNumber, sum = 0;
if(argc != 3)
{
printf("Missing argument!\n");
exit(1);
}
infile = fopen(argv[1], "r");
if(infile != NULL)
{
outfile = fopen(argv[2], "w");
if(outfile == NULL)
{
printf("Error, cannot open the outfile!\n");
abort();
}
else
{
while(!feof(infile))
{
number = getNumber(infile);
if(number == NULL)
{
free(number);
abort();
}
newNumber = strtol(number, &pEnd, 10);
sum += newNumber;
if(!*pEnd)
printf("Converted successfully!\n");
else printf("Conversion error, non-convertible part: %s", pEnd);
fprintf(outfile, "%d\n", newNumber);
free(number);
}
fprintf(outfile, "\nSum: %d\n", sum);
}
}
else
{
printf("Error, cannot open the infile!\n");
abort();
}
fclose(infile);
fclose(outfile);
return 0;
}
char *getNumber(FILE *infile)
{
char *number, *number2;
int length, cursor = 0, c;dwwd
number = (char*)malloc(sizeof(char)*CHUNK);
if(number == NULL)
{
printf("Error!\n");
return NULL;
}
length = CHUNK;
while(!isspace(c = getc(infile)) && !feof(infile))
{
if(isdigit(c))
{
number[cursor] = c;
cursor++;
if(cursor >= length)
{
length += CHUNK;
number2 = (char*)realloc(number, cursor);
if(number2 == NULL)
{
free(number);
return NULL;
}
else number = number2;
}
}
}
number[cursor] = '\0';
return number;
}
I would be really grateful for any help.
I am also sending two files, input_file and output_file:
Your condition here:
while(!isspace(c = getc(infile)) && !feof(infile))
Breaks every time you encounter space. After that you will always print the number. That means that for every interval(also for the end of the file) that is not preceded directly with digit you will print one extra zero in the output file.
Maybe add one flag whether you entered the while at least once. If you have not - just do not print anything.
You have to add else statement to your if(isdigit(c)) to break the loop when a non digit character is found after having found a digit previously.
if(isdigit(c))
{
// your existing code
}
else if (cursor != 0)
{
break;
}
Hope this helps.
EDIT:
Just replace
fprintf(outfile, "%d\n", newNumber);
with
if(0 != newNumber) fprintf(outfile, "%d\n", newNumber);
From the strtol c library manpage:
If there were no digits at all, strtol() stores
the original value of nptr in *endptr (and returns 0)
You always assign to newNumber and don't check for the case where strtol doesn't actually return a converted number but a instead returns a 0 because it couldn't find a number. That's why you have all the zeroes in your output file.
Related
Program should read list of filenames, open these files and put their handles in the array of structure, then read strings and print consecutive lines of strings to smallest files by using handles contained in array of structures.
My program puts data from all lines to only one file which is initially the smallest which is false because it should the one which is smallest with every time it prints data into the file. This is my program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <math.h>
struct file_t
{
FILE* f;
int size;
}t[5];
void close_file(struct file_t* f) {
if (f == NULL || f->f == NULL) {
}
else {
fclose(f->f);
}
}
int open_file(struct file_t* f, const char* filename) {
if (f == NULL || filename == NULL) {
return 1;
}
FILE* fp;
fp = fopen(filename, "ab");
if (fp == NULL) {
return 2;
}
long int res = ftell(fp);
fclose(fp);
f->size = res;
f->f = fopen(filename, "ab+");
if (fp == NULL) {
return 2;
}
return 0;
}
struct file_t* find_min(const struct file_t* files, int size) {
if (files == NULL || size <= 0) {
return NULL;
}
int x = (files + 0)->size, i = 0, index = 0;
for (i = 0; i < size; i++) {
if ((files + i)->size <= x) {
x = (files + i)->size;
index = i;
}
}
return (struct file_t*)(files + index);
}
int main() {
puts("Input files' names:");
char tab[100];
int num = 0;
while(1==1){
if(fgets(tab, 100, stdin)==NULL||*tab=='\n'){
if (num == 0) {
printf("Couldn't open file");
return 4;
}
break;
}
int index=strlen(tab);
*(tab+index-1)='\x0';
if (strlen(tab) > 30) {
*(tab + 30) = '\x0';
}
if (open_file((t + num), tab) > 0) {
}
else {
num++;
}
}
if (num == 0) {
printf("Couldn't open file");
return 4;
}
char str[1000];
printf("Input text:");
*str = '\x0';
while (fgets(str, 1000, stdin)==NULL||*str!='\n') {
int index=strlen(str);
*(str+index-1)='\x0';
struct file_t* p = find_min(t, num);
fwrite(str, sizeof(char), strlen(str), p->f);
}
for (int i = 0; i < num; i++) {
close_file(t + i);
}
printf("File saved");
return 0;
}
There are some critical bugs that you need to resolve.
fseek(stdin, 0, SEEK_END) -- fseek normally only work on a disk file, or something reasonably similar. Please refer to this link Using fseek with a file pointer that points to stdin
As a matter of fact even fflush() won't work. fflush is something that is designed for flushing output streams, and its behavior with input streams is implementation-dependent. Please refer to this link for more details stdinflush
scanf("%[^\n]s", tab)
If you are using this in a loop or multiple times, only the first read will succeed. The reason being, the \n character is left out from the previous input, and as said earlier fflush() might not be successful in removing that \n. The further calls to scanf() will simply return without reading anything.
'\0x' If you are intending to use this as string terminator then this is not it. It is a multi-character constant with an integer value 120. Below is a vague test run
Code
#include <stdio.h>
int main()
{
if ('\0' == '\0x' )
printf("both are same\n");
printf("%d",'\0x');
}
Compilation Warnings
test.c: In function ‘main’:
test.c:5:14: warning: multi-character character constant [-Wmultichar]
5 | if ('\0' == '\0x' )
| ^~~~~
test.c:8:14: warning: multi-character character constant [-Wmultichar]
8 | printf("%d",'\0x');
| ^~~~~
Output
120
fseek(fp, 0, SEEK_END); ftell(fp); -- This should not be used to determine the file sizes. The behavior of the fseek() with SEEK_END is undetermined in the case of binary files. Please refer to this link Do not use fseek() and ftell() to compute the size of a regular file
Some Logic Errors
1) You should compute the file size every time in find_min() as it gets changed whenever you write data to the file.
2) fwrite()won't actually dump the data to file immediately. you need to call fflush().
After resolving the above issues, this is the modified code.
Code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <math.h>
#include <sys/stat.h>
struct file_t
{
FILE* f;
int size;
}t[5];
void close_file(struct file_t* f) {
if (f == NULL || f->f == NULL) {
}
else {
fclose(f->f);
}
}
int open_file(struct file_t* f, const char* filename) {
if (f == NULL || filename == NULL) {
return 1;
}
f->f = fopen(filename, "a");
if (f->f == NULL)
return 2;
struct stat statbuf;
fstat(fileno(f->f), &statbuf);
f->size = statbuf.st_size;
return 0;
}
struct file_t* find_min(const struct file_t* files, int size) {
if (files == NULL || size <= 0) {
return NULL;
}
struct stat statbuf;
fstat(fileno(files->f), &statbuf);
int x = statbuf.st_size, i = 0, index = 0;
for (i = 0; i < size; i++) {
fstat(fileno((files+i)->f), &statbuf);
if (statbuf.st_size < x) {
x = statbuf.st_size;
index = i;
}
}
return (struct file_t*)(files + index);
}
int main() {
puts("Input files' names:");
char tab[100];
int num = 0;
while(1){
int c;
while (1) {
c = getc(stdin);
if (c == EOF || c == ' ')
goto user_input;
if(c != '\n')
break;
}
tab[0] = c;
if (scanf("%[^\n]s", tab+1) == EOF)
break;
if (*tab == '\0') {
if (num == 0) {
printf("Couldn't open file");
return 4;
}
break;
}
if (strlen(tab) > 30) {
*(tab + 30) = '\0';
}
if (open_file((t + num), tab) > 0) {
}
else {
num++;
}
*tab = '\0';
}
user_input:
if (num == 0) {
printf("Couldn't open file");
return 4;
}
fflush(stdin);
char str[1000];
printf("Input text:\n");
*str = '\0';
while(1) {
int c;
while(1) {
c = getc(stdin);
if (c == EOF)
goto main_exit;
if (c != '\n')
break;
}
str[0] = c;
if (scanf("%[^\n]s", str+1) == EOF)
break;
struct file_t* p = find_min(t, num);
fwrite(str, sizeof(char), strlen(str), p->f);
fflush(p->f);
}
main_exit:
for (int i = 0; i < num; i++) {
close_file(t + i);
}
printf("File saved");
return 0;
}
Terminal Session
$ ./a.out
Input files' names:
test file1.txt
test file2.txt
' '(NOTE: Space character inputted before pressing enter.)
Input text:
this is
stackoverflow
File saved
test file1.txt
this is
test file2.txt
stackoverflow
Note for breaking from the first loop (Files input). You need to enter space and then press enter (You can tweak around this).
Where are you updating the file_t->size when you write into a file?
You are calling this:
fwrite(str, sizeof(char), strlen(str), p->f);
But after that you should do p->size += strlen(str) to update its size, otherwise all file sizes are set to initial values, and hence all strings get written to a single file.
As for getting garbage data, try printing the string you are reading from scanf in the while loop.
You are using scanf to read characters until '\n', but you are not reading the '\n' itself. You need a fseek(stdin, 0, SEEK_END); in that loop as well.
Finally, why are you using syntax like this:
(files + i)->size
When you can call it more cleanly like this:
files[i].size
You code is really hard to read because of this.
I need to read data store in end of file and print it.
My input file has many numbers, and I have to read last number,
can any one help me??
int main()
{
FILE *fp;
fp = fopen("f:\\Issuance.csv", "a");
if (!fp)
{
printf("can not open file \n");
getchar();
exit(1);
}
int Size = 30;
char FileInfo[100];
fseek( fp , 0 , SEEK_END);
fread(FileInfo, 1, Size, fp);
printf("%d",FileInfo);
}
fcloseall();
}
You need to use the 2nd parameter of fseek().
fseek(fp, -Size, SEEK_END);
fread(FileInfo, 1, Size, fp);
FileInfo[Size] = '\0'; // NULL terminate FileInfo; or declare as char FileInfo[100] = {0};
printf("%s", FileInfo);
To read the last number in a text file (which may have additional junk after it), starting from the beginning, attempt to read a number. If successful, save it, else toss 1 char. Continue until the end of the file.
// Read last number
int ReadLastNumber(FILE *inf, int default_value) {
int last = default_value;
int num;
int cnt;
rewind(inf);
while ((cnt = fscanf(inf,"%d", &num)) != EOF) {
if (cnt == 1) {
last = num;
} else {
fgetc(inf); // toss non-numeric char
}
}
return last;
}
A more sane solution would fseek() to the end, search backwards for digits. Once some digits are found, continue backwards looking for digits, +or -. Something like the following untested code.
#include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
// Read last number
int ReadLastNumber2(FILE *inf, int default_value) {
int last = 0;
int place = 1;
bool digit_found = false;
long offset = -1;
while (fseek(inf, offset, SEEK_CUR) == 0) {
int ch = fgetc(inf);
if (ch == EOF) // Likely I/O error
return default_value;
if (isdigit(ch)) {
digit_found = true;
last += (ch - '0')*place;
place *= 10;
offset = -2;
} else if (ch == '-') {
return -last;
} else if (digit_found) {
return last;
}
}
return default_value;
}
Not protected against int overflow.
I have this small program in C that reads through a file a compares word by word,
how can I assure that words like "this," won't be read as a word? I would like it to read as "this"
int main(int argc, char *argv[]) {
if(argc != 3)
{
printf("Usage: ./sw <word> <filename> \n");
exit(1);
}
char* word = argv[1];
const char* filename = argv[2];
FILE* file = fopen(filename, "r");
if(file == NULL)
{
printf("Could not open file\n");
exit(1);
}
//Assuming one word can not have more than 250 chars
char w[250], check_eof;
do
{
check_eof = fscanf(file, "%s", w);
if(strcmp(word, w) == 0)
{
printf("W : %s \n", w);
}
} while(check_eof != EOF);
fclose(file);
return 0;
}
You can check if a char belongs to a word like this
int c = fgetc(file);
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
// c belongs to a word
word[n++] = c;
} else {
// end of word
if (strncmp(word, w, n) == 0) {
// word and w match!
}
}
If you #include <ctype.h>, then you can call isalpha(c) instead to test it.
In the code below, I use isalpha() and I copy the result string in a new buffer named res. However, this procedure can be done in-place, but I'll leave now for the sake of simplicity.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h> // for isalpha()
int main(int argc, char *argv[]) {
char* word = "this";
const char* filename = "test.txt";
FILE* file = fopen(filename, "r");
if(file == NULL)
{
printf("Could not open file\n");
exit(1);
}
//Assuming one word can not have more than 250 chars
// ATTENTION, it is 249 chars, do NOT forget of the null terminator
char w[250], res[250];
int check_eof; // should be of type int, for EOF checking
do
{
check_eof = fscanf(file, "%s", w);
// what if 'word' appears as the last word
// in the file? You should check for eof
// right after fscanf()
if(check_eof == EOF)
break;
int i = 0, j = 0;
while (w[i]) // parse what we read
{
if (isalpha(w[i]))
res[j++] = w[i]; // keep only the alphabetic chars
i++;
}
res[j] = '\0'; // it should be a null terminated string
if(strcmp(word, res) == 0) // compare to 'res' now
{
printf("W : %s \n", res);
}
} while(1); // the terminating step is inside the body now
fclose(file);
return 0;
}
I want to write a program which print all numbers found in a file and then add them up. I have two problems:
How to add up the numbers I've printed?
Why in output_file do I have so many commas:
Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define CHUNK 12
char *getWord(FILE *infile);
void clean(char *dirty);
char *getWord(FILE *infile)
{
char *word, *word2;
int length, cursor, c;
word = (char*)malloc(sizeof(char)*CHUNK);
if(word == NULL) return NULL;
length = CHUNK;
cursor = 0;
while(!isspace(c = getc(infile)) && !feof(infile))
{
word[cursor] = c;
cursor++;
if(cursor >= length)
{
length += CHUNK;
word2 = (char*)realloc(word, cursor);
if(word2 == NULL)
{
free(word2);
return NULL;
}
else
{
word = word2;
}
}
}
word[cursor] = '\0';
return word;
}
void clean(char *dirty)
{
int i = 0, j = 0;
char *temp;
temp = strdup(dirty);
while(i < strlen(temp))
{
if(isdigit(temp[i]))
{
dirty[j] = temp[i];
j++;
}
i++;
}
dirty[j] = '\0';
free(temp);
}
int main(int argc, char *argv[])
{
char *word;
FILE *infile, *outfile;
if(argc != 3)
{
printf("Missing argument!\n");
exit(1);
}
infile = fopen(argv[1], "r");
if(infile != NULL)
{
outfile = fopen(argv[2], "w");
if(outfile == NULL)
{
printf("Error, cannot open the outfile!\n");
abort();
}
else
{
while(!feof(infile))
{
word = getWord(infile);
if(word == NULL)
{
free(word);
abort();
}
clean(word);
fputs(word, outfile);
fputs(",", outfile);
free(word);
}
}
}
else
{
printf("Error, cannot open the outfile!\n");
abort();
}
fclose(infile);
fclose(outfile);
return 0;
}
infile:
You are getting , because of this -
fputs(",", outfile);
It is related in structure to the echo unix command. The core of the program could be simplified to something along the following lines:
int c, need_comma = 0;
while ((c = fgetc(infile)) != EOF) {
if (isdigit(c)) {
fputc(c, outfile);
need_comma = 1;
}
else {
if (need_comma == 1) {
fputc(',', outfile);
need_comma = 0;
}
}
}
this removes the need for getWord and clean functions.
This is just the printing part. the intermediate file is in CSV format,
which is structured and easy to parse and add the numbers (and print the
result to another file).
I just got a semi function head program running and I need help making it into a tail program where it will display x number of lines at the end of the file. Here is my head code.
I'm having trouble thinking of how to get the counter to read the entire file then start at the bottom and show the last lines of the file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 1024
int numLines = 0;
int linecount = 0;
FILE *src = NULL;
char ch[MAX];
void GetArgs (int argc, char **argv){
if(argc != 4 || argc != 2) {
printf("Error not enough arguments to continue \n", argv[0]);
exit(-1);
}// end if argc doenst = 4 or 2
if(argc == 2){
src = fopen( argv[1], "r:");
numLines=10;
}// end argc = 2
if(argc == 4){
if (strcmp (argv[1], "-n") !=0 ){
numLines = atoi (argv[2]);
src = fopen (argv[3], "r");
if ( src == NULL){
fputs ( "Can't open input file." , stdout);
exit (-1);
}
while (NULL != fgets(ch, MAX, src)){
linecount++;
fputs(ch, stdout);
if (linecount == numLines){
break;
}
}
}//end of nested if
else if (strcmp (argv[2], "-n") !=0 ){
numLines = atoi (argv[3]);
src = fopen (argv[1], "r");
if ( src == NULL){
fputs ( "Can't open input file." , stdout);
exit (-1);
}
while (NULL != fgets(ch,MAX, src)){
linecount++;
fputs(ch, stdout);
if (linecount == numLines){
break;
}
}
}//end of else
}//end if argc == 4
}// end GetArgs
int main(int argc, char **argv){
GetArgs(argc, argv);
fclose( src );
}
You can keep a counter to pass through the whole file and count the total number of lines (Only call fgets to read one line at a time). Suppose N is the total number of lines and n is the number of last lines to be shown on the screen. Then start again at the beginning of the file pass through N - n lines without showing them on the screen (i.e. dont call fputs), after that call fputs for n number of times.
I used your variables and style. If I understand, you want to printout last [X] lines from file. [X] - parameter from CLI
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAX 1024
FILE *src = NULL;
FILE *src_end = NULL;
int linecount = 0;
char ch[MAX];
int main(int arc, char **argv) {
int i = 0;
int letter = 0;
if (arc != 4) {
puts("Wrong parameters");
return 1;
}
do {
src = fopen(argv[1], "r");
if (src == NULL) {
puts("Can't open input file.");
break;
}
if (0 != strcmp(argv[2], "-n")) {
puts("Wrong 2nd parametr");
break;
}
sscanf(argv[3], "%u", &linecount);
printf("Printout last %u lines, from file:%s\n", linecount,
argv[1]);
src = fopen(argv[1], "r");
if (src == NULL) {
fputs("Can't open input file.", stdout);
return 1;
}
for (i = 2; linecount; i++) {
fseek(src, -i, SEEK_END);
letter = fgetc(src);
if (letter == 0x0a) { // 0x0a == "\n"
fgets(ch, MAX, src);
fputs(ch, stdout);
linecount--;
}
}
} while (0);
fclose(src);
return 1;
}