I am making a program for a class that reads the contents of a .csv file. I am using a while loop inside of a for loop to scan the contents into two separate arrays, and when it prints the contents, everything is right, except it is missing the first letter in the file. We are not allowed to use any functions from the library except what is permitted.
Code in question:
void readFile(FILE *fptr, int size)
{
int i, a;
a = size / 2;
printf("number of lines in readFile is %d:\n", size);
double y[50];
char x[50];
for (i = 0; i < a; i++)
{
while (fscanf(fptr,"%c,%lf,", &x[i], &y[i]) ==2);
}
printf("%c, %.2lf: ", x[0], y[0]);
//a loop to make sure it scanned properly by displaying array contents
for (i = 0; i < a; i++)
{
printf("%c, %.2lf:\n", x[i], y[i]);
}
}
I tried with no luck to !feof(fptr), != EOF, but these are not supposed to be used in the intro class I am taking. I am out of ideas to fix it.
This is the output of the program above:
number of lines in readFile is 4:
, 20.00:
, 20.00:
E, 30.00:
number of lines is 4:
A few issues ...
The fscanf format is wrong. It needs a leading space to skip over newlines.
Unless you intend to operate on the data read in readFile (vs. passing it back to caller), having function scoped x and y arrays will go out of scope when the function returns.
The caller of readFile should pass the maximum array count but let the function determine the actual number of entries.
Whenever I see two or more "parallel" arrays [indexed by the same variable], I would use a struct. Particularly for .csv data.
.csv files are of the form: a,b\nc,d\n and not a,b,\nc,d,\n so the trailing , in the fscanf is incorrect.
Using nested loops for the data input doesn't work.
No need for feof. Just loop until the fscanf return is not 2.
Here is the corrected code. It is annotated:
#include <stdio.h>
#include <stdlib.h>
// data for single .csv line
struct data {
char x;
double y;
};
// readFile -- read in .csv file
// RETURNS: count of records/lines read
size_t
readFile(FILE *fptr, struct data *arr, size_t size)
// fptr -- open file stream
// arr -- pointer to data array
// size -- maximum number of elements in arr
{
int count = 0;
while (1) {
// check for overflow of array
if (count >= size) {
fprintf(stderr,"readFile: too much data for array\n");
exit(1);
}
// point to current struct/record
struct data *cur = &arr[count];
// read in the .csv line -- stop on error or EOF
if (fscanf(fptr, " %c,%lf", &cur->x, &cur->y) != 2)
break;
// advance the count of the number of valid elements
++count;
}
return count;
}
int
main(int argc,char **argv)
{
struct data arr[50];
// skip over program name
--argc;
++argv;
if (argc != 1) {
printf("wrong number of arguments\n");
exit(1);
}
// open the input file
FILE *fptr = fopen(argv[0],"r");
if (fptr == NULL) {
perror(argv[0]);
exit(1);
}
// read in the data lines
size_t count = readFile(fptr,arr,sizeof(arr) / sizeof(arr[0]));
fclose(fptr);
// print the array
for (size_t idx = 0; idx < count; ++idx) {
struct data *cur = &arr[idx];
printf("%c, %.2f:\n",cur->x,cur->y);
}
return 0;
}
Here is the sample input I used to test the program:
J,23
D,37.62
F,17.83
Here is the program output:
J, 23.00:
D, 37.62:
F, 17.83:
Related
Okay! Pretty new to this stuff!
This is part of a bit bigger task and the problem I have now is that I have a list of names (100 names) inside a text file. They're written like this:
Sam (enter) Oliver (enter) Paul (enter) --- and so on.
So every name is on its own row. I'm trying to read this into a char array which I'll then print out to check if it works. I'll have to do something else to it afterward but I want to figure that out later.
Here's my code right now: (File names etc. are in Finnish so don't bother with that! :D)
#include <stdio.h>
int main() {
FILE *tiedosto;
char *array[100];
char nimi[] = "names.txt";
tiedosto = fopen(nimi, "r");
if (tiedosto == NULL) {
printf("Tiedostoa ei voida avata");
return;
}
int i;
for (i = 0; i < 100; i++) {
fscanf(tiedosto, "%s", &array[i]);
}
fclose(tiedosto);
printf("Tulostetaan taulukko \n");
// printf("%s \n",array);
for (i = 0; i < 100; i++) {
printf("%s \n", array[i]);
}
return 0;
}
You have got several errors in the code:
In this line:
fscanf(tiedosto, "%s", &array[i]);
You don't need to use an ampersand sign here. It's because the array is already the type of char*[] – in such situations, you must avoid passing char**.
In the following code segment:
if (tiedosto == NULL) {
printf("Tiedostoa ei voida avata");
return; // ***
}
The return type of the main() is an integer, so it must pass something non-void. Any non-zero return code would indicate an unsuccessful program closure.
In this declaration:
char *array[100];
The array is using a pointer alongside the array too. Thus this must be initialized using the malloc() function properly so that you don't hit with a segfault.
In case you don't want to get messed up of allocating memory, etc. try switching to two-dimensional array declaration:
char array[TOTAL_ENTRIES][PER_NAME_LEN];
I have described the 2-D array approach to avoid code complexity (read comments for explanation):
#include <stdio.h>
// Some global macros throughout this program
#define MAX_USERS 100
#define MAX_STRLEN 64
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
int main(void) {
const char *file_name = "names.txt";
FILE *fp = fopen(file_name, "r");
char name_list[MAX_USERS][MAX_STRLEN];
int count = 0;
// Using perror() is the best option here
if (fp == NULL) {
perror(file_name);
return EXIT_FAILURE;
}
// Reading the file contents and saving that into 2-D array
while (fscanf(fp, "%s", name_list[count++]) != EOF)
;
// Displaying the saved array contents
for (int i = 0; i < count - 1; i++)
fprintf(stdout, "%s\n", name_list[i]);
return 0;
}
In this program, the number of lines in the names.txt file can be anything lesser than or equal to 100.
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;
}
I have a queue with int numbers, the goal is to print all elements sorted. First, I save all numbers in a txt file, and then I use the shell command "sort" to print all of them sorted. It's possible to do this in a cleaner way? (without using files, and if it's possible without system(...);)
This is the code:
...
FILE* fp=fopen("numbers.txt","w+");
printf("\n");
while (!empty(&my_queue)) //while queue is not empty
{
elem = first(&my_queue); //first() gets and deletes first element of queue
fprintf(fp,"%d\n", elem->number);
}
fclose(fp);
system("sort -n < numbers.txt");
remove("numbers.txt");
}
Thanks!
Supposing your numbers are floats listed separate lines of your file:
Create an array of float. If your don't know how many numbers you have, use a very large array (Note: in the example below, I created an array number_array of size 100)
Read your file
For each line of your file, store the number in the array you created in step 1
After reading the whole file, sort the array. Note that in the example below, I use the function qsort to sort the array (see manual with command man qsort ;) )
Write the content of your sorted array in your file
Example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define LINE_SIZE 1024
// Comparison function used for sorting
int compare (const void * a, const void * b)
{
float fa = *(float*) a;
float fb = *(float*) b;
return (fa > fb) - (fa < fb);
}
// -------------------------------------------------------------
int main()
{
FILE *f;
char line[LINE_SIZE], *p;
int i = 0, j;
// YOUR NUMBER ARRAY
float number_array[100];
// Open file
if (!(f = fopen("numbers.txt", "r"))) {
fprintf(stderr, "Unable to open file argument\n");
return 1;
}
// Read lines from file
while (fgets(line, LINE_SIZE, f)) {
// You may want to remove the trailing '\n'
if ((p = strchr(line, '\n'))) { *p = '\0'; }
// Skip empty lines
if (line[0] == '\0') { continue; }
// Adding number to array
number_array[i] = atof(line);
i++;
}
// Closing file
fclose(f);
// Sorting array
qsort (number_array, i, sizeof(float), compare);
// Displaying result 8-)
// for (j=0; j<i; j++)
// {
// printf("%0.2f ", number_array[j]);
// }
// printf("\n");
// Writing sorted result to file
if (!(f = fopen("numbers.txt", "w"))) {
fprintf(stderr, "Unable to open file argument\n");
return 1;
}
for (j=0; j<i; j++)
{
fprintf(f, "%0.2f\n", number_array[j]);
}
fclose(f);
return 0;
}
I was wondering how to properly read a file and place each line in a string of arrays in C.
I have a file with the following written on it
one
two
three
four
I tried writing something like this:
int read_file(FILE *fp){
char readLine[MAX_LEN];
char *myarray[20];
int counter =0;
int i =0;
while(fgets(readLine,MAX_LEN,fp) != NULL){
myarray[counter] = readLine;
counter++;
}
/*printing the array*/
while(i<counter){
printf("%d %s",i,myarray[i]);
i++;
}
}
and the main would be something like
int main(){
FILE *fp;
fp = fopen("my.txt","r");
if(fp == NULL){
fprintf(stderr,"File does not exist");
return EXIT_FAILURE;
}
read_file(fp);
}
however, when printing I get:
four
four
four
four
even when I print using printf("%s",myarr[2]) , I still get four
Anyone knows what the problem may be?
You really need to make a copy of the line (by way of strdup()) as you are overwriting the buffer used to accept the input:
int read_file(FILE *fp){
char readLine[MAX_LEN];
char *myarray[20]; // Note char pointer!
int i, counter = 0;
while (counter < 20 && fgets(readLine,MAX_LEN,fp) != NULL) { // Note limit!
myarray[counter] = strdup(readLine);
counter++;
}
/*printing the array*/
for (i = 0; i < counter; i++)
printf("%d %s",i,myarray[i]);
/* free the lines */
for (i = 0; i < counter; i++)
free(myarray[i]);
}
myarray[counter] = readLine;
is the problem. You are overriding the read line pointer values each time.
use strcpy to copy the buffer content instead.
In addition as commented: you are not declaring array of strings, merely one string.
Change it to:
char myarray[4][20];
Of course, 4 is an example. Change it to any number of lines or use dynamic allocation.