I`m making a file reader that reads integers numbers line by line from a file. The problem is that is not working. I think I am using fscanf in a wrong way. Can someone help me?
I had already look for answers in others questions but I can`t find anything that explain why I my code is not working.
int read_from_txt(){
FILE *file;
file = fopen("random_numbers.txt", "r");
//Counting line numbers to allocate exact memory
int i;
unsigned int lines = 0;
unsigned int *num;
char ch;
while(!feof(file)){
ch = fgetc(file);
if (ch == '\n'){
lines++;
}
}
//array size will be lines+1
num = malloc(sizeof(int)*(lines+1));
//storing random_numbers in num vector
for(i=0;i<=lines;i++){
fscanf(file, "%d", &num[i]);
printf("%d", num[i]);
}
fclose(file);
}
The txt file is like:
12
15
32
68
46
...
But the output of this code keeps giving "0000000000000000000..."
You forgot to "rewind" the file:
fseek(file, 0, SEEK_SET);
Your process of reading goes through the file twice - once to count lines, and once more to read the data. You need to go back to the beginning of the file before the second pass.
Note that you can do this in a single pass by using realloc as you go: read numbers in a loop into a temporary int, and for each successful read expand the num array by one by calling realloc. This will expand the buffer as needed, and you would not need to rewind.
Be careful to check the results of realloc before re-assigning to num to avoid memory leaks.
You could try to use the getline function from standard IO and add the parsed numbers into the array using only one loop. See the code below. Please check https://linux.die.net/man/3/getline
Also, you can use the atoi or strtoul functions to convert the read line to an integer. Feel free to check https://linux.die.net/man/3/atoi or https://linux.die.net/man/3/strtoul
The code below evaluate a file with a list of numbers and add those numbers to a C integer pointer
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char ** argv) {
FILE * file;
file = fopen("./file.txt", "r");
size_t read;
char * line = NULL;
size_t line_len = 0;
size_t buffer_size = 10;
int * buffer = (int *)malloc(sizeof(int) * buffer_size);
int seek = 0;
while((read = getline(&line, &line_len, file)) != -1) {
buffer[seek++] = atoi(line);
if (seek % 10 == 0) {
buffer_size += 10;
buffer = (int *)realloc(buffer, sizeof(int) * buffer_size);
}
}
for (int i = 0; i < seek; i++) {
printf("%d\n", buffer[i]);
}
free(buffer);
fclose(file);
}
If you aren't sure which conversion function should you use. You can check the difference between atoi and sscanf at What is the difference between sscanf or atoi to convert a string to an integer?
Related
I'm trying to do some simple tasks in C and run them from the command line in Linux.
I'm having some problems with both C and running the code from the command line with a given filename given as a parameter. I've never written code in C before.
Remove the even numbers from a file. The file name is transferred to
the program as a parameter in the command line. The program changes
this file.
How do I do these?
read from a file and write the results over the same file
read numbers and not digits from the file (ex: I need to be able to read "22" as a single input, not two separate chars containing "2")
give the filename through a parameter in Linux. (ex: ./main.c file.txt)
my attempt at writing the c code:
#include <stdio.h>
int main ()
{
FILE *f = fopen ("arr.txt", "r");
char c = getc (f);
int count = 0;
int arr[20];
while (c != EOF)
{
if(c % 2 != 0){
arr[count] = c;
count = count + 1;
}
c = getc (f);
}
for (int i=0; i<count; i++){
putchar(arr[i]);
}
fclose (f);
getchar ();
return 0;
}
Here's a complete program which meets your requirements:
write the results over the same file - It keeps a read and write position in the file and copies characters towards the file beginning in case numbers have been removed; at the end, the now shorter file has to be truncated. (Note that with large files, it will be more efficient to write to a second file.)
read numbers and not digits from the file - It is not necessary to read whole numbers, it suffices to store the write start position of a number (this can be done at every non-digit) and the parity of the last digit.
give the filename through a parameter - If you define int main(int argc, char *argv[]), the first parameter is in argv[1] if argc is at least 2.
#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
if (argc < 2) return 1; // no argument given
FILE *f = fopen(argv[1], "rb+");
if (!f) return 1; // if fopen failed
// read, write and number position
long rpos = 0, wpos = 0, npos = 0;
int even = 0, c; // int to hold EOF
while (c = getc(f), c != EOF)
{
if (isdigit(c)) even = c%2 == 0;
else
{
if (even) wpos = npos, even = 0;
npos = wpos+1; // next may be number
}
fseek(f, wpos++, SEEK_SET);
putc(c, f);
fseek(f, ++rpos, SEEK_SET);
}
ftruncate(fileno(f), wpos); // shorten the file
}
I'd do that like this (removing extra declarations => micro optimizations)
/**
* Check if file is avaiable.
*/
if (f == NULL)
{
printf("File is not available \n");
}
else
{
/**
* Populate array with even numbers.
*/
while ((ch = fgetc(f)) != EOF)
ch % 2 != 0 ? push(arr, ch); : continue;
/**
* Write to file those numbers.
*/
for (int i = 0; i < 20; i++)
fprintf(f, "%s", arr[i]);
}
Push implementation:
void push(int el, int **arr)
{
int *arr_temp = *arr;
*arr = NULL;
*arr = (int*) malloc(sizeof(int)*(n - 1));
(*arr)[0] = el;
for(int i = 0; i < (int)n - 1; i++)
{
(*arr)[i + 1] = arr_temp[i];
}
}
In order to write to the same file, without closing and opening it, you should provide both methods, w+ (writing and reading), and this method will clear it's content.
So, change the line where you open the file, for this.
FILE *f = fopen ("arr.txt", "w+");
You should look for ways of implementing dynamic arrays (pointers and memory management).
With this example you could simply go ahead and write yourself, inside the main loop, a temporary variable that stores a sequence of numbers, and stack those values
Something like this (pseudocode, have fun :)):
DELIMITER one of (',' | '|' | '.' | etc);
char[] temp;
if(ch not DELIMITER)
push ch on temp;
else
push temp to arr and clear it's content;
Hope this was useful.
I have written a program in C to represent a quiz game. Each question is an individual line of a text file. I am using a struct to represent the array of questions. It begins by taking some user input, then counts the amount of text lines in the file. It then allocated the amount of memory needed for the structs before reading each line of the file into the struct. When I print out the elements in the struct it prints out 20 lines of errors instead of the file values. What am I doing incorrectly? I have included a screenshot of some of lines of the file also.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#define filepath "Questions_Answers"
#define CAPACITY 120
typedef struct
{
char* questions;
} Lines;
int setupGame(int *difficulty);
int main() {
int difficulty; //Set difficulty out of ten of the quiz
int numberOfLines = 0; //Set the number of lines counted in the file initially to zero
int question_length;
char answer[20];
char c;
//Calls setup game function which sets the difficulty
difficulty = setupGame(&difficulty);
FILE* fPointer = fopen(filepath, "r"); //Points to the address of a File not yet known
//If the file has no content, print error and end program
if (fPointer == NULL) {
perror("Error opening file");
return -1;
}
// Extract characters from file and store in character c
for (c = getc(fPointer); c != EOF; c = getc(fPointer)) {
if (c == '\n') // Increment count if this character is newline
numberOfLines++;
}
numberOfLines = numberOfLines + 1;
printf("Number of questions in quiz - %d\n", numberOfLines);
Lines *lines = malloc(sizeof(Lines) * numberOfLines); // allocate memory for questions
for (int i = 0; i < numberOfLines; i++) {
int lengthOfQuestion = 150;
lines[i].questions = malloc(sizeof(char) * (lengthOfQuestion + 1));
fscanf(fPointer, "%s", lines[i].questions);
printf("%s\n", lines[i].questions);
}
fclose(fPointer);
for (int i = 0; i < numberOfLines; i++) {
free(lines[i].questions);
}
free(lines);
return 0;
}
You have to fclose(fPointer); then reopen before you want to get questions from the file.
fclose(fPointer);
fPointer = fopen("input.txt", "r");
fscanf reads word by word not whole the line. You should use fgets() or getline().
I see in your code, you init the length of all questions by 150
int lengthOfQuestion = 150;
So, i think, it's easier when you declare the struct (you can use pointer if you want):
typedef struct
{
char questions[150];
} Lines;
You should use one loop for storing and increasing the number of lines. The code will be more readable. For example:
char line[150];
lines = malloc(sizeof(Lines));
if(!lines) {// handle the error}
while (fgets(fPointer, sizeof(line), line)) {
strcpy(lines[numberOfLines].question, line);
numberOfLines++;
lines = realloc(lines, sizeof(Lines) * numberOfLines);
if(!line) {// handle the error}
}
I want my program to read N words from a text file and save them in an array. My question is, do i need a 2D Array e.g: char **wordList or is the 1D Array in the example below sufficient? The output is correct except from the last string which as you can see is weird. Also, am i allocating sufficient memory for the array and why does the last output string come out wrong?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void populateWordsArray(int);
FILE *file;
char *word;
char **wordList;
/*
* Function populateWordsArray: reads N words from
* the given file and creates an array with them.
* Has one argument: int N - the number of words to read.
*/
void populateWordsArray(int N) {
int i = 0;
while(!feof(file) && i < N) {
fscanf(file,"%s",&word[i]);
printf("%s\n",&word[i]);
i++;
}
}
int main(int argc,char *argv[]) { // argv[1] = op argv[2] = name
int N = 0;
file = fopen(argv[2],"r");
if(file == (FILE *) NULL) { // check if the file opened successfully
fprintf(stderr,"Cannot open file\n");
}
fscanf(file,"%d",&N); // get the N number
word = malloc(N * sizeof(char));
populateWordsArray(N);
// write a switch method for the various ops
// call the appropriate function for each operation
free(word);
fclose(file);
return 0;
}
Output:
this
is
a
test!
with
files.
new
line,
here.
ere.
text file content:
10 this is a test! with files.
new line, here.
Your example is wrong. When executing the line fscanf(file,"%s",&word[i]);, the third argument should be the address where the function will write the read data. In your case, word[i] is the i-th element of the array and &word[i] is its address. So, the word will be stored with the first character at the word[i]. Your code only prints something because you print it immediately. Also, you don't get a segfault by pure chance.
If you want to read a string into a buffer, you first need to allocate the space for the buffer.
By using char **, you can make it into a 2D array by first allocating sufficient space for the array of pointers and then allocate sufficient space for each of the pointers to hold an address to a string.
I have rewritten your program for you:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_STRING_LENGTH 100
void populateWordsArray(int);
FILE *file;
char **wordList;
void populateWordsArray(int N)
{
int i = 0;
while(i < N && fscanf(file,"%s", wordList[i]) == 1) // fscanf returns the number of successfully read items. If it's not 1, the read failed. You can also check if the return value is not EOF but, in this situation, it's the same.
{
printf("%s\n", wordList[i]); // i-th element is an address to a buffer that contains 100 bytes
i++;
}
}
int main(int argc,char *argv[])
{
int N = 0, i;
file = fopen(argv[1],"r"); // Indexing starts from 0 in C. Thus, 0th argument is the executable name and 1st is what you want.
if(file == NULL) // No need to cast NULL into a specific type.
{
fprintf(stderr,"Cannot open file\n");
return 1; // You might want to end the program here, possibly with non-zero return value.
}
fscanf(file,"%d",&N);
wordList = malloc(N * sizeof(char*)); // Allocating space for pointers
for(i=0; i<N; i++)
{
wordList[i] = malloc(MAX_STRING_LENGTH); // Allocating space for individual strings
}
populateWordsArray(N);
for(i=0; i<N; i++)
{
free(wordList[i]);
}
free(wordList);
fclose(file);
return 0;
}
I'd also advise against using global variables here.
EDIT: As the comments may suggest, this code is not the best solution. First, all the words might not fit into a 100 byte buffer. To alleviate this issue, allocate a large, fixed-size buffer, read every word into it, then allocate corresponding number of bytes for wordList[i] (don't forget the terminating null byte) and copy the data from the fixed-size buffer into wordList[i].
Also, the code has some missing error checks. For instance, the file may exist but is empty, in which case fscanf(file,"%d",&N); will return EOF. Also, the number at the beginning of the file may not be corresponding to the number of the lines that follow or N might be a negative number (the code allows for it by specifying it to be int).
EDIT2: As #bruno suggested, I made a version that I think is more bulletproof than the previous one. It's possible that I omitted something, I'm in a bit of a hurry. If so, let me know below.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_STRING_LENGTH 512
char line_buffer[MAX_STRING_LENGTH]; // A line of the maximum size that can occur.
char** populateWordsArray(unsigned wantedLines, FILE* file, unsigned *readLines);
char** populateWordsArray(unsigned wantedLines, FILE* file, unsigned *readLines)
{
*readLines=0;
char** wordList;
// Allocating space for pointers
wordList = malloc(wantedLines * sizeof(char*));
if(!wordList)
{
fprintf(stderr,"Cannot allocate sufficient space for the pointers.\n");
exit(EXIT_FAILURE); // You may return NULL here and check it afterwards. The same goes for all the error checking inside this function
}
while(*readLines < wantedLines && fscanf(file,"%s", line_buffer) == 1)
{
wordList[*readLines] = malloc(strlen(line_buffer)+1);
if(!wordList[*readLines])
break;
if(NULL == (wordList[*readLines]=strdup(line_buffer)))
break;
(*readLines)++;
}
return wordList;
}
int main(int argc,char *argv[])
{
unsigned N = 0, i, M;
char **wordList;
FILE *file;
file = fopen(argv[1],"r"); // Indexing starts from 0 in C. Thus, 0th argument is the executable name and 1st is what you want.
if(file == NULL) // No need to cast NULL into a specific type.
{
fprintf(stderr,"Cannot open file\n");
return 1; // You might want to end the program here, possibly with non-zero return value.
}
if(fscanf(file,"%d",&N) != 1)
{
fprintf(stderr,"Cannot read the number of lines. Empty file?\n");
return 1;
}
wordList = populateWordsArray(N, file, &M);
printf("Printing the read lines:\n");
for(i=0; i<M; i++)
{
printf("%s\n", wordList[i]);
}
for(i=0; i<M; i++)
{
free(wordList[i]);
}
free(wordList);
fclose(file);
return 0;
}
void inputData()
{
FILE* fp = fopen("input_001.txt", "r");
if(fp == NULL)
{
exit(FILE_FAILED_TO_OPEN);
}
fseek(fp, 0, SEEK_END); //set position to end of file
int size = ftell(fp);
if(size == 0)
{
exit(PARSING_ERROR_EMPTY_FILE);
}
int i;
char *input;
char *errPtr = NULL;
char *data;
fgets(input, 64, fp);
for(i = 0; i < size; i++)
{
strtol(input[i], *errPtr, 10);
//testing the output
printf("%d\n", input[i]);
}
fclose(fp);
if(fclose(fp) != 0)
{
exit(FILE_FAILED_TO_CLOSE);
}
}
I am trying to input data from a text file of unknown size into an array and keep only the integers. The format of the text file is one number per line and there can be any number of lines. I have included my attempt at trying to input the data, but my coding was not going so well. I want to use fgets() and then strtol() to convert the lines I get from fgets() into integers and put them in an array so I can work with that data. Any help is appreciated!
You haven't allocated any space for input to point to. I saw your
earlier version had a malloc; you can use that, or just a char
array.
Did you mean to use data? Because you're not, yet.
fgets reads at most one line at a time, so you need to put your reads
in a loop.
You appear to be converting the string to a number multiple times. For
instance, if the first line were "12345", this code would get 12345,
then 2345, 345, etc. This was presumably not your intention.
You're incrementing i up to size. size is the file size and might
be quite large, but you only read a maximum of 64 characters into the
buffer. (Or would have, if space had been allocated.)
In short, this code is very confused and I recommend starting over from
scratch. Decide whether you want to read the entire file at once, or one
line at a time; I recommend the latter, it takes less memory and is
simpler. If you want to store them in an array, you can do that with
malloc and then realloc as needed to grow the array dynamically.
do not use strtol, use atoi instead.
and use a loop to read the lines.
just a quick answer:
int count = 0;
while( fgets (input, 64, fp) != NULL )
{
count++;
}
fseek(fp, 0, SEEK_SET);
int* arr = new int[count];
count = 0;
while( fgets (input, 64, fp) != NULL )
{
int a =atoi(input);
arr[count++] = a;
}
If you don't know how many lines are in the file, you have a few options:
Loop through the file, counting the number of lines (call it nlines). Then declare the array int numbers[nlines].
Use a linked list instead of an array to store the numbers.
Dynamically allocate blocks of an array.
As for reading the integer data itself, something like this would work if you decide to go with the first option:
void inputData(const char* fname, const unsigned int nlines)
{
FILE* fp = fopen(fname, "r");
if (fp == NULL) {
exit(EXIT_FAILURE);
}
int numbers[nlines];
double d = 0;
fscanf(fp, "%lf", &d);
int i = 0;
while (!feof(fp)) {
numbers[i++] = (int)floor(d);
fscanf(fp, "%lf", &d);
}
fclose(fp);
}
I need to write a code that will print the frequency of each word from a given file. Words like "the" and "The" will count as two different words. I've written some code so far but the command prompt stops working when I try to run the program. I just need some guidance and to be pointed in the best direction for this code, or I would like to be told that this code needs to be abandoned. I'm not very good at this so any help would be very appreciated.
#include <stdio.h>
#include <string.h>
#define FILE_NAME "input.txt"
struct word {
char wordy[2000];
int frequency;
} words;
int word_freq(const char *text, struct word words[]);
int main (void)
{
char *text;
FILE *fp = fopen(FILE_NAME, "r");
fread(text, sizeof(text[0]), sizeof(text) / sizeof(text[0]), fp);
struct word words[2000];
int nword;
int i;
nword = word_freq(text, words);
puts("\nWord frequency:");
for(i = 0; i < nword; i++)
printf(" %s: %d\n", words[i].wordy, words[i].frequency);
return 0;
}
int word_freq(const char *text, struct word words[])
{
char punctuation[] =" .,;:!?'\"";
char *tempstr;
char *pword;
int nword;
int i;
nword = 0;
strcpy(tempstr, text);
while (pword != NULL) {
for(i = 0; i < nword; i++) {
if (strcmp(pword, words[i].wordy) == 0)
break;
}
if (i < nword)
words[i].frequency++;
else {
strcpy(words[nword].wordy, pword);
words[nword].frequency= 1;
nword++;
}
pword = strtok(NULL, punctuation);
}
return nword;
}
First off all:
char *text;
FILE *fp = fopen(FILE_NAME, "r");
fread(text, sizeof(text[0]), sizeof(text) / sizeof(text[0]), fp);
Reads probably 4 bytes of your file because sizeof(text[0]) is 1 and sizeof(text) is probably 4 (depending on pointer size). You need to use ftell() or some other means to get the actual size of your data file in order to read it all into memory.
Next, you are storing this information into a pointer that has no memory allocated to it. text needs to be malloc'd or made to hold memory in some way. This is probably what is causing your program to fail to work, just to start.
There are so so SO many further issues that it will take time to explain them:
How you are using strcpy to blow up memory when you place it intotempstr
How even if that weren't the case, it would copy probably the whole file at once, unless the file had NULL terminated strings within, which it may, so perhaps this is ok.
How you compare nwords[i].wordy, even though it is not initialized and therefore garbage.
How, even if your file were read into memory correctly, you look a pword, which is unitialized for your loop counter.
Please, get some help or ask your teacher about this because this code is seriously broken.