Why does getw not display all of the numbers in the file? - c

I have followed this tutorial to implement a program that generates up to 100,000 random numbers and inserts them in a file to be sorted, but I have noticed that the loop with getw is outputting way less numbers than expected. In my machine, this code only prints 49 numbers:
#include <stdio.h>
#include <stdlib.h>
int gen_random_file(int n_values) {
int index;
int num, num_count = 0;
FILE *r_file;
r_file = fopen("random_numbers", "w");
if (r_file != NULL) {
printf("File created successfully!\n");
}
else {
printf("Failed to create the file.\n");
return -1;
}
for (index = 0; index < n_values; index++) {
putw(rand(), r_file);
}
fclose(r_file);
r_file = fopen("random_numbers", "r");
// display numbers
printf("\nNumbers:\n");
while ( (num = getw(r_file)) != EOF ) {
printf("%d\n", num);
num_count++;
}
printf("\nEnd of file.\nNum Count = %d\n", num_count);
fclose(r_file);
return 0;
}
int main()
{
gen_random_file(10000);
return 0;
}

You terminate the loop too early. rand() is likely to produce -1 once in a while.
Quoting man getw (section Bugs):
Since EOF is a valid integer value, feof(3) and ferror(3) must be used to check for failure after calling getw().
You need something like
while(1) {
if ((w = getw()) == EOF) {
if (feof(stdin) || ferror(stdin)) {
break;
}
printf(....);
....
}
// Deal with error if necessary

This one of those rare cases where you actually want feof. You need a loop like
while ((num = getw(r_file)), !feof(r_rile)) {
to read a number and then test for EOF.
On some systems (such as Windows), you'll also need "wb" and "rb" for your fopen modes to get a binary file.

I ended up using fwrite and fread as well as "wb" and "wr" as parameters for fopen and that solved the problem.
#include <stdio.h>
#include <stdlib.h>
int gen_random_file(int n_values) {
int index;
int rand_num, num_count = 0;
int buffer[100000];
FILE *rand_file;
rand_file = fopen("random_numbers", "wb");
if (rand_file != NULL) {
printf("File created successfully!\n");
}
else {
printf("Failed to create the file.\n");
return -1;
}
for (index = 0; index < n_values; index++) {
rand_num = rand();
fwrite(&rand_num, sizeof(rand_num), 1, rand_file);
}
fclose(rand_file);
rand_file = fopen("random_numbers", "rb");
// display numbers
printf("\nNumbers:\n");
fseek(rand_file, 0, SEEK_SET);
fread(buffer, sizeof(rand_num), n_values, rand_file);
for (index = 0; index < n_values; index++) {
rand_num = buffer[index];
printf("%d\n", rand_num);
num_count++;
}
printf("\nEnd of file.\nNum Count = %d\n", num_count);
fclose(rand_file);
return 0;
}
int main()
{
gen_random_file(10000);
return 0;
}

Related

Works when executed as main, but not when called by main

I was attempting to read a CSV file with the readCsv() function defined below. I happened to observe that when the readCsv() function is called within the main() function,
I end up experiencing a runtime error and the function readCsv() fails to work properly. By contrast, when I instead rename the readCsv() function to main() (of course having commented the main()
function first), the program works perfectly. But now I'm stuck because I need to be able
to call the readCsv() function within main().
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int readCsv(void)
{
int n = 0;
while(n == 0)
{
do{
printf("Enter the index of the student you want to query:");
scanf("%i",&n);
while(getchar() != '\n')
{
continue;
}
}while((isdigit(n)) != 0);
}
n++;
FILE* fp;
fp = fopen("students.csv","r+");
if ((fp == NULL)) exit(1);
char buffer[1024];
int row,column = 0;
while(fgets(buffer,1024,fp))
{
column = 0;
row++;
if(row != n)
{
continue;
}
else if (row == n)
{
char* value = strtok(buffer,",");
while(value)
{
if (column == 0)
{
printf("\nIndex:");
}
if (column == 1)
{
printf("\tName:");
}
if (column == 2)
{
printf("\tAge:");
}
if (column == 3)
{
printf("\tphone:");
}
printf("%s",value);
value = strtok(NULL,",");
column++;
}
printf("\n");
break;
}
else
{
printf("None of the conditions are true");
break;
}
}
fclose(fp);
return 0;
}
void main(void)
{
readCsv();
}
It's easy to get lost when one function tries to do everything: file open/close, user input, read from file, search for target, output results, handle problems.
Here's a snippet of your function modified to demonstrate how these operations may be handled in a more obvious (imho) sequence.
bool found = false;
while( !found && fgets(buffer,1024,fp) )
{
if( atoi( buffer ) == n ) // 'Index' is first value of each row
found = true;
}
fclose(fp);
if( !found )
{
printf("None of the conditions are true");
return 0;
}
int column = 0;
char* value = strtok(buffer,",");
/*
output fields of this row that are in buffer[]
Or, pass buffer[] to a separate function that prints the fields.
*/
return 1;

Print the user input strings into a least sized user input files

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.

Why my string getting some extra value? (C program)

I am trying to solve a C Program problem:
Create a program in C that reads a string from a text file and then reorders the string in an odd-even format (first take odd numbered letters and then even numbered letters; example: if the program reads elephant, then the reordered string will be eehnlpat). Then write the string in a different text file. Provide an error-checking mechanism for both reading and writing.
My code is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
FILE *inputFile;
inputFile = fopen("inpFile.txt", "r");
if (inputFile != NULL) {
FILE *outFile = fopen("outFile.txt", "w");
if (outFile != NULL) {
printf("file created successfully\n");
int i, j = 0;
char strf1[50];
fscanf(inputFile, "%s", &strf1);
char strf2[strlen(strf1)];
for (i = 0; strf1[i] > 0; i++) {
if (i % 2 == 0) {
strf2[j] = strf1[i];
j++;
}
}
for (i = 1; strf1[i] > 0; i++) {
if (i % 2 == 1) {
strf2[j] = strf1[i];
j++;
}
}
fprintf(outFile, "%s\n", strf2);
fclose(outFile);
} else {
printf("file could not be created\n");
}
fclose(inputFile);
} else {
printf("File does not exist.");
}
return 0;
}
I feel all is OK but the problem is if the program reads elephant, then the reordered string given by my program is eehnlpatZ0#. Where extra Z0# is my problem. I don't want that extra thing. But I can't fix it. If anybody can help me to fix it, that will be great.
Your target string is too short: char strf2[strlen(strf1)];. You should at least allow for a null terminator and set it, or simply make the output array the same size as the input array:
char strf2[50];
There are other problems in your code:
In case of error by fopen, it would be advisable to return a non-zero status to the system.
You should pass the array to fscanf(), not a pointer to the array, which has a different type.
You should tell fscanf() the maximum number of characters to read into the array with %49s
You should test the return value of fscanf() and produce an empty output file for an empty input file. The current code has undefined behavior in this case.
The test strf1[i] > 0 is incorrect: characters from the input file might be negative. You should either compute the string length or test with strf1[i] != '\0'
Starting the second loop at i = 1 seems a good idea, but it relies on the silent assumption that strf1 is not an empty string. In your example, if fscanf() succeeds, strf1 is not empty, and if it fails the behavior is undefined because strf1 is uninitialized. Yet it is safer to avoid such optimisations which will bite you if you later move the code to a generic function for which the assumption might not hold.
You must null terminate the output string before passing it to fprintf or specify the length with a %.*s format.
Here is a corrected version:
#include <stdio.h>
int main() {
FILE *inputFile, *outFile;
char strf1[50], strf2[50];
int i, j;
inputFile = fopen("inpFile.txt", "r");
if (inputFile == NULL) {
printf("Cannot open input file inpFile.txt\n");
return 1;
}
outFile = fopen("outFile.txt", "w");
if (outFile == NULL) {
printf("Could not create output file outFile.txt\n");
fclose(inputFile);
return 1;
}
printf("file created successfully\n");
if (fscanf(inputFile, "%49s", strf1) == 1) {
j = 0;
for (i = 0; strf1[i] != '\0'; i++) {
if (i % 2 == 0)
strf2[j++] = strf1[i];
}
for (i = 0; strf1[i] != '\0'; i++) {
if (i % 2 == 1)
strf2[j++] = strf1[i];
}
strf2[j] = '\0';
fprintf(outFile, "%s\n", strf2);
}
fclose(inputFile);
fclose(outFile);
return 0;
}
Here is an alternative with simpler copy loops:
int len = strlen(strf1);
j = 0;
for (i = 0; i < len; i += 2) {
strf2[j++] = strf1[i];
}
for (i = 1; i < len; i += 2) {
strf2[j++] = strf1[i];
}
strf2[j] = '\0';
You have to provide a space for the null-terminator, since you did not provide a space for it, printf cannot know when your string is terminated, so it contiues to print out data from the memory.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE* inputFile;
inputFile=fopen("inpFile.txt", "r");
if (inputFile!=NULL) {
FILE* outFile=fopen("outFile.txt", "w");
if (outFile!=NULL) {
printf("file created successfully\n");
int i, j=0;
char strf1[50];
fscanf(inputFile, "%s",&strf1);
int inputLength = strlen(strf1) + 1;
char strf2[inputLength];
char strf2[inputLength-1] = '\0';
for(i=0; strf1[i]>0; i++) {
if(i%2==0) {
strf2[j]=strf1[i];
j++;
}
}
for(i=1; strf1[i]>0; i++) {
if(i%2==1) {
strf2[j]=strf1[i];
j++;
}
}
fprintf(outFile, "%s\n",strf2);
fclose(outFile);
}else{
printf("file could not be created\n");
}
fclose(inputFile);
}
else {
printf("File does not exist.");
}
return 0;
}
In C, strings require a Null character, '\0', as the last byte in order to terminate.
Changing the following line of code from
char strf2[strlen(strf1)];
to
char strf2[strlen(strf1) + 1];
will solve this problem.

Count how many integers are in the text file using fscanf

For example, I have a txt file with all integers. I want to count how many integers there are in order to allocate an array.
int array[0];
int count = 0;
FILE *file = fopen("file1.txt","r");
while(fscanf(file,"%d",&array[count])==1){
count++;
}
printf("%d",count);
Currently there are error messages and won't go through. Is this the way fscanf work?
You cannot create an array of size 0. If you want to only count the number of integers, don't use an array, but only a temporary variable.
It is a good idea to check whether you opened the file correctly and to close the file too.
#include <stdio.h>
int main(){
int temp;
int count = 0;
FILE *file = fopen("file1.txt","r");
if(file == NULL){
printf("Could not open specified file");
return -1;
}
while(fscanf(file,"%d",&temp)==1){
count++;
}
fclose(file);
printf("%d",count);
}
return 0;
}
If you also want to store the values for later use, you could for example read through the file twice, first time counting the amount of integers, then using this amount to declare the needed array. An important thing before the second run is to rewind the file pointer, to read the file from the start.
#include <stdio.h>
int main(){
int temp;
int count = 0;
FILE *file = fopen("file1.txt","r");
if(file == NULL){
printf("Could not open specified file");
return -1;
}
while(fscanf(file,"%d",&temp)==1){
count++;
}
printf("%d",count);
if(count == 0){ //do not create array of size 0
fclose(file);
}
else{
//second run
int array[count];
rewind(file);
for(int i=0; i<count; i++){
fscanf(file,"%d",&array[count]);
}
fclose(file);
//continue using array...
}
return 0;
}
int array[0];
and
fscanf(file,"%d",&array[count])
will lead to a segmentation fault because you're accessing the array out of bounds.
If you need flexible array you need
int *array
a place-holder for storing each number from fscanf
realloc array every time you find a new number and add the number to array.
#include <stdio.h>
#define isDigit(c) ('0' <= (c) && (c) <= '9') ? 1 : 0
int main() {
FILE *fd;
int counter, c, tmp;
if ((fd = fopen("PathToFile", "r")) != NULL){
do{
c = getc(fd);
if (isDigit(c)) tmp = 1;
else if (tmp == 1 && !isDigit(c)){
counter++, tmp = 0;
}
}while (c != EOF);
}else{
printf("Couldn't find File!");
return 1;
}
fclose(fd);
printf("%i", counter);
return 0;
}

C Program that takes pairs of numbers from a file, calculates newton(n,k), and writes answer to another file

I need a help with a program that takes pairs of numbers from a txt file, calculates the Newton coefficient (n! / (n! . (n-k)!)), and writes the answer (score) to the other txt file. For now I have this:
#include <stdio.h>
void factorial() {
long l1, l2;
long score = 1;
for (int i = 1; i < l2; i++) {
score = (score * (l1 - i + 1) / i);
}
}
void read() {
long l1, l2;
long score = 1;
FILE *file = fopen("pairs.txt", "r");
FILE *file2 = fopen("sum.txt", "r");
while (fscanf(file, "%ld%ld", &l1, &l2) == 2) {
factorial();
fprintf(file2, "%ld", score);
}
printf("Score is: %ld", score);
fclose(file);
fclose(file2);
}
int main() {
read();
return 1;
}
The problem is that when I start the program it shows me answer Score is: 1, and there is nothing in the file sum.txt.
There are multiple problems in your code:
You must pass arguments to the binomial function, return the result with the return statement and store the return value in the calling code.
Your function to compute the Newton binomial coefficients is incorrect.
You should open the output file sum.txt for writing with the "w" mode string.
You should check if fopen() succeeded at opening the files. As posted, your code probably fails to open the output file sum.txt that does not exist because it tries to open it for reading. Hence file2 is NULL and invoking fprintf with a null stream pointer has undefined behavior. This would explain the crash you observe.
Here is a corrected version:
#include <errno.h>
#include <stdio.h>
#include <string.h>
long binomial(long n, long k) {
long value = 1;
if (k < n - k) {
k = n - k;
}
for (long i = n; i > k; i--) {
value *= i;
}
for (long i = k; i > 1; i++) {
value /= i;
}
return value;
}
int read(void) {
long n, k, score;
FILE *file1, *file2;
file = fopen("pairs.txt", "r");
if (file == NULL) {
fprintf(stderr, "error opening pairs.txt: %s\n", strerror(errno));
return 1;
}
file2 = fopen("sum.txt", "w");
if (file2 == NULL) {
fprintf(stderr, "error opening sum.txt: %s\n", strerror(errno));
fclose(file);
return 1;
}
while (fscanf(file, "%ld%ld", &n, &k) == 2) {
score = binomial(n, k);
fprintf(file2, "%ld\n", score);
}
//printf("Score is: %ld\n", score);
fclose(file);
fclose(file2);
return 0;
}
int main(void) {
return read();
}
Why are you opening a file and printing the results in the terminal using printf, when you want the output to be stored in another file? If you want to put output of a program in a file, Redirection is done using the "<" operator(for stdin).
Also there is a segmentation fault when running your program(your fscanf line).
Can you show us a version of your input file(pairs.txt) ?

Resources