reading data from text file and add it into array - c

I tried to read the data from a text file and add it to an array. However, it raises an error ["Warning:" assignment makes integer from pointer without a cast]. I declared fp is a variable of FILE, and already open text file with read-only mode.
char arrRequest[100];
char strRow[10];
int i = 0;
.....................
void request(){
for (;;){
fgets(strRow, 10, (FILE *)fp);
i = i + 1;
arrRequest[i] = strRow; // it raises an error here
printf("value of %d is %s:\n", i, arrRequest[i]);
}
}
Could you please tell me why it happens?
Thanks.

In your code, you declared:
char arrRequest[100];
char strRow[10];
But in for loop:
arrRequest[i] = strRow;
It means you assign a character to an array of character. So it raises an error here.
If you want to copy a string, you should usestrcpy function. You can declare an array of pointer or 2D array as the comment above:
char arrRequest[100][10]
// using strcpy
strcpy(arrRequest[i], strRow);
Or
char * arrRequest[100]
// allocate for each arrRequest element
arrRequest[i] = malloc(strlen(strRow)*sizeof(char) + 1);
if (!arrRequest[i])
// Handle error
OT, you should use while loop to stop reading the file if there is nothing still to read. You can use for loop as you used in your code, but have to stop reading until you meet EOF. Do not need to cast fp if you declare FILE *fp before.
while(fgets(strRow, 10, fp);)

Related

C File pointer returns the contents of a file twice

With the following program, I wish to read a file (say, a text file) and store all of it's contents in a variable. So, to achieve it, I cooked up the following with the help of Stack Overflow suggestions. However, this program returns the contents of a file twice.
For instance, let the following program read a text file with the following contents:
John Start 0
Using *,15
Then, the program will display the following:
John Start 0
Using *,15
John Start 0
Using *,15
Thus, I would like your help in finding out the problem. Thanks a lot in advance!
//Program to read a file and store it's contents in a single variable
#include<stdio.h>
#include<ctype.h>
#include<string.h>
#include<stdlib.h>
/*Reads contents of a file and returns address of variable, in which file contents are stored*/
char* fileRead(char*);
//Concatenates 2 strings
char* concat(char*,char*);
//Calculates the size of the file
unsigned long fsize(char* file);
int main()
{
char *prt, *out;
//Allocate memory & take the input of the file name to read
prt = malloc(256);
printf("\nEnter the name of the file : \t");
scanf("%255s",prt);
//Copy the address of read data & output it
out = fileRead(prt);
printf("\nContents : \n-----------------\n%s", out);
free(out);
free(prt);
return 0;
}
char* fileRead(char *file)
{
//function to read the contents of a file
FILE *fip;
char *text, *temp, read[1024];
int size, i=0;
fip=fopen(file, "r");
size=(int)fsize(file);
temp = malloc(size*10);
text = temp;
//If the file doesn't exist then...
if(fip==NULL)
{
temp = strdup("ERROR : File doesn't exist! Please try again!\n");
return temp;
}
//Begin concatenation, once after the file reading has been initiated
while(fgets(read, 1024, fip) != NULL)
{
temp = concat(text,read);i++;
}
fclose(fip);
return text;
}
char* concat(char* dest, char* src)
{
//function to concatenate src to dest
while(*dest) dest++;
while(*dest++ = *src++);
return --dest;
}
unsigned long fsize(char* file)
{
//calculates the size of file
FILE * f = fopen(file, "r");
fseek(f, 0, SEEK_END);
unsigned long len = (unsigned long)ftell(f);
fclose(f);
return len;
}
Edit 1: Thanks a lot people. For your quick response& efficient answers. As for the size*10 thing, it was a random idea, I came up with, to deal with one of the Segmentation Fault errors. Never thought the size+1 option. I've learned a lot from you all. Will come with a new question soon. Thanks again!
Your problem is that you use "text" as a string but failed to do it.
A "string" in C is a char array terminated by '\0'.
If you use any string related function, you have to unsure that you give string !
So after you allocated "text" (througth "temp"), "text" is not yet a string since it doesn't contain '\0'.
Since it's an "empty" string at the beginning, you have to initialize by doing
text[0] = '\0';
Now, why your file is printed twice ? Dunno, but I have to bet on an UB since your string wasn't properly initialized.

Segmentation Fault after reading a file into a struct array

I am trying to write a program that reads data from a file and puts it into a struct array. I have succeeded in putting it into the array but I then get a segmentation fault. I believe I have to use malloc to initialize the struct array but I am new to programming and don't really understand how to do this. Thanks for your help! I have copied pieces of my code so you can see what I've done. I have not included my functions in this code.
struct Weather
{
char location;
int daynum;
double temp;
double precip;
};
int main (void)
{
FILE*openFile;
char buffer[COLS][ROWS];
int i = 0;
struct Weather loc1; //initialize here?
for (i = 0; i <200; i++)
{
fgets (buffer[i], ROWS, openFile);
parseLine(buffer[i], &loc1);
printf ("%d %c %d %.2lf %.2lf\n",i, loc1.location, loc1.daynum, loc1.temp, loc1.precip);
}
}
Your file stream (openFile) is not initialized; it does not actually point to a file. As yano said in his comment, use fopen() in order to properly initialize the file pointer.
You must initialize the file stream with fopen() before any I/O operations!
int main()
{
char filename[64];
FILE *fp;
snprintf(filename, sizeof(filename), "hello1234.txt");
if(NULL == (fp = fopen(filename, "r")))
{
printf("err, failed when fopen(), %s %s[%d].\n", __FILE__, __FUNCTION__, __LINE__);
return -1;
}
//your code here
return 0;
}
Initialize the struct
Note that malloc() cannot initialize the struct.
two methods:
M0:
struct Weather loc1;
memset(&loc1, 0, sizeof(struct Weather));
M1:
struct Weather loc1 = {0};
man malloc or click the link for a malloc manual.
Multiple problems in your code:
The stream pointer openFile is uninitialized, calling fgets() for it invokes undefined behavior. You want to open a file for fopen() or set the value of openFile to the standard input stream stdin.
The 2D char array should be defined in the other order:
char buffer[ROWS][COLS];
you should use the same constant for the loop counter and the 2D array definition: ROWS might be defined to something less than 200.
the size of the line buffer is COLS, pass that to fgets().
you should test the return value of fgets(): it returns NULL at end of file and the contents of the destination array is indeterminate in this case.
whether or not to initialize loc1 depends on what the parseLine() function does. It would make sense that parseLine() make no assumptions about the contents of the destination structure, but the source has not been posted, so we cannot know for sure.
the printf format specifier for type double is %f, the extra l is simply ignored.

How to overwrite a preallocated char array in C

I initialize a char array as a global variable in my C program with a default file location/name as
char file[] = "/home/jack/files/data.txt";
Later in the program, if a condition is satisfied I read a file containing a new file name
int read_new_file(char *fname)
{
FILE *inp;
char buffer[255];
char oldFile[127], newFile[127];
inp = fopen(fname, "r");
while ( fgets(buffer, 255, inp) != NULL )
{
sscanf(buffer, "%s %s",oldFile,newFile);
file = newFile; // <---- Is this wrong/unsafe?
}
return 0;
}
I should note that it is assumed file fname only contains one line with 2 strings. This was just to show the general framework of the code. My question, as highlighted in the code, is it wrong or unsafe to simply try and reassign the char file variable with the new string?
The size of the newFile string will likely differ from it's original default size. The default has to be predefined, since the condition may not require a new file to be read. If the assignment is wrong or unsafe, what is a better approach?
You need to declare file so it's large enough to hold newFile.
char file[127] = "/home/jack/files/data.txt";
Then when you want to update it, you use:
strcpy(file, newFile);
file = newFile; // <---- Is this wrong/unsafe?
It is wrong since file is an array. The compiler won't let you do that.
Whether it is safe or not is not relevant since you can't do it.
Use strcpy instead.
strcpy(file, newFile);

How do I read lines from a file in C?

I need to read in a file. The first line of the file is the number of lines in the file and it returns an array of strings, with the last element being a NULL indicating the end of the array.
char **read_file(char *fname)
{
char **dict;
printf("Reading %s\n", fname);
FILE *d = fopen(fname, "r");
if (! d) return NULL;
// Get the number of lines in the file
//the first line in the file is the number of lines, so I have to get 0th element
char *size;
fscanf(d, "%s[^\n]", size);
int filesize = atoi(size);
// Allocate memory for the array of character pointers
dict = NULL; // Change this
// Read in the rest of the file, allocting memory for each string
// as we go.
// NULL termination. Last entry in the array should be NULL.
printf("Done\n");
return dict;
}
I put some comments because I know that's what I'm to do, but I can't seem to figure out how to put it in actual code.
To solve this problem you need to do one of two things.
Read the file as characters then convert to integers.
Read the file directly as integers.
For the first, you would use freed into a char array and then use atoi to convert to integer.
For the second, you would use fscanf and use the %d specify to read directly into an int variable;
fscanf does not allocate memory for you. Passing it a random pointer as you have will only cause trouble. (I recommend avoid fscanf).
The question code has a flaw:
char *size;
fscanf(d, "%s[^\n]", size);
Although the above may compile, it will not function as expected at runtime. The problem is that fscanf() needs the memory address of where to write the parsed value. While size is a pointer that can store a memory address, it is uninitialized, and points to no specific memory in the process' memory map.
The following may be a better replacement:
fscanf(d, " %d%*c", &filesize);
See my version of the spoiler code here

Error reading char* type from .DAT file with C

So, for some reason, I need to make a external file (.DAT) to store data by appending the new one to the end of old data.
#include <stdio.h>
#include <stdlib.h>
int main () {
typedef struct {
char *Name;
int Index;
} DataFile;
static FILE *file;
size_t result;
DataFile *DataTable;
file = fopen("database.DAT","ab");
DataTable = (DataFile *) malloc (sizeof(DataFile));
DataTable[0].Name = "somefile.txt";
DataTable[0].Index = 7;
printf("%s %d \n",DataTable[0].Name,DataTable[0].Index);
result = fwrite(DataTable,sizeof(DataFile),1,file);
fclose(file);
free(DataTable);
return 0;
}
After running code above, I then check if the data stored correctly. So, I make this code below.
#include <stdio.h>
#include <stdlib.h>
int main () {
typedef struct {
char *Name;
int Index;
} DataFile;
static FILE *file;
size_t result;
long size;
int i;
DataFile *DataTable;
file = fopen("database.DAT","rb");
if (file == NULL) printf("Error1");
// Determine the size of file
fseek(file,0,SEEK_END);
size = ftell(file);
rewind(file);
DataTable = (DataFile *) malloc ((size/sizeof(DataFile)) * sizeof(DataFile));
if (DataTable == NULL) printf("Error2");
result = fread(DataTable,sizeof(DataFile),size/sizeof(DataFile),file);
fclose(file);
for (i=0; i<result; i++) {
printf("%s %d \n",DataTable[i].Name,DataTable[i].Index);
}
free(DataTable);
return 0;
}
However, it gives output
somefile.txt 7
from the first code block and
Error1 7
from the second code block.
I notice that the problem is not because the failure either when opening .DAT file or when allocating memory for DataTable. Also, it works for int type (Index) but not for char* type (Name) when reading from .DAT file. I have no idea what to do to solve this char*-type-reading problem (and where 'error1' comes from). (not even google gives me answer.)
Your structure DataFile stores one pointer and one integer. When you write it to the file, you write some program specific pointer to a string, and an integer.
When reading from it, you just refill your structure with the pointer and the integer, wich means that DataFile.Name will be a pointer to a probably-not-initialized memory segment. But since you created your file pointing to the first hard-coded string ("filename.txt"), some undefined but understandable behaviour happens, and your pointer in this case points to the first hard-coded string you wrote in you second program (which in your case is Error1)
What you really want to do is write the real string in your file.
A simple solution, if you want to the keep the hole writing structure thing is to create an array instead of a pointer
typedef struct {
char Name[512];
int Index;
} DataFile;
then initialize your data with
strncpy(DataTable[0].Name, "somefile.txt", sizeof(DataTable[0].Name) - 1); // just to make sure you dont overflow your array size
DataTable[0].Name[sizeof(DataTable[0].Name) - 1] = '\0';
and retreview your data the way you did.
A char* is only a pointer, i.e. the address of the character array containing your strings. You don't write the strings themselves to the file. After reading the file, as the same strings aren't in your memory at the same addresses any more, the application will fail.
You'll have to come up with a way to save the strings themselves to file as well. Probably by first writing their length, and then writing their content. Upon reading, you can use the length information to allocate memory dynamically, then read into that memory.
In your writing code you haven't allocated storage for char *Name. When you perform the DataTable[0].Name = "somefile.txt" instruction you're not actually copying the "somefile.txt" into memory pointed by Name, it's actually assigning a Name a value pointing to a constant characters string (moreover, it will become dangling pointer since the string is an rvalue, i.e. doesn't have a memory to be addressed via). Same goes for your file reading code.
You need to:
Allocate storage for your Name.
Copy the string using memcpy or similar into the allocated storage.

Resources