How can I retrieve an array of floating-point values from a file in C? This is the code I have used so far, but I am running into a segmentation fault(marked in my code where). If you see a less painful way of doing this that would be helpful as well.
The values are stored in the file with a single space after each value like so:
-667.0897114275529 544.6798599456312 -148.0586015260273 -323.4504101541069 .
// open file
FILE *fp;
fp = fopen(sig_file, "r");
if (fp == NULL){
printf("File opened incorrectly or is empty");
return 1;
}
// find file size
fseek(fp, 0L, SEEK_END);
long sz = ftell(fp);
fseek(fp, 0L, SEEK_SET);
// store file contents to f_contents
char *f_contents = 0;
f_contents = malloc(sz);
if (f_contents){
fread(f_contents, 1, sz, fp);
}
fclose(fp);
if (f_contents){
// find how many points are in the file
long pt_count = 0;
int i;
for (i=0; i<sz; i++){
if (f_contents[i] == ' '){
pt_count++;
}
}
// store points to a float array
double signal[pt_count];
char *pt;
pt = strtok(f_contents, " ");
// seg fault 11:
if (pt == NULL){
printf("error with pt");
return 1;
}
signal[0] = atof(pt);
//
for (i=1; i<pt_count; i++){
pt = strtok(NULL, " ");
signal[i] = atof(pt);
}
}
free(f_contents);
If you see a less painful way of doing this that would be helpful as well.
I haven't studied your code enough to identify the source of the segfault, because it should just be rewritten anyway. I might be inclined to do something more like this:
// open file
FILE *fp = fopen(sig_file, "r");
if (fp == NULL){
perror("fopen");
return 1;
}
size_t sz = 0;
for (int c = getc(fp); c != EOF; c = getc(fp)) {
if (c == ' ') sz++;
}
rewind(fp);
double signal[sz];
for (size_t i = 0; i < sz; i++) {
if (fscanf(fp, "%lf", &signal[i]) != 1) {
fclose(fp);
fputs("I/O error, malformed input, or premature EOF\n", stderr);
return 1;
}
}
fclose(fp);
If the file is long, then it might be worthwhile to read it all in one pass instead of counting elements first (and especially instead of slurping the entire file into memory). You can achieve such a one-pass read by storing the values in a more flexible data structure: some variety of linked list, or a dynamically allocated (and reallocated as necessary) array.
A linked list would need to be postprocessed into array form, but you might be able to use a dynamically allocated array as-is. You would need to use either a dynamically allocated array or a large-enough fixed-size array with a C implementation that does not support variable-length arrays, such as MS Visual Studio.
The first argument to strtok() must be a null-terminated string. fread() doesn't add a null terminator, and even if it did, you didn't allocate enough space for f_contents to hold it.
So use this code to allocate and fill in f_contents
f_contents = malloc(sz+1);
if (f_contents){
fread(f_contents, 1, sz, fp);
f_contents[sz] = '\0';
}
fclose(fp);
Related
I have a file .txt containing some values formatted like this:
0,30,25,10
Now, I open up the file and store it into an array
char imposta_tratt[300];
FILE *fp;
fp = fopen("/home/pi/Documents/imposta_trattamento.txt", "r");
if (fp == 0) return;
fread(imposta_tratt, sizeof(imposta_tratt), 1, fp);
fclose(fp);
Now I expect to have the array filled with my data. I have the values separated by a , so I go on and parse it:
const char delim[2] = ",";
int t=0;
char *token = strtok(imposta_tratt, delim);
while (token!=NULL){
strcpy(tratt[t],token);
token = strtok(NULL, delim);
tratt[t]=token;
t++;
}
Here, referring to what's in the file .txt, I expect to have tratt[0]=0; tratt[1]=30; tratt[2]=25; and so on, but seems like I am missing something since it's not like this.
All I want is to have the values of the txt file stored in single variables. Can someone help?
What you are trying to achieve can simply be done using fgets():
bool read_file_content(const char *filename, const size_t tsizemax, int tratt[tsizemax], size_t *tsize, const char *delim)
{
// Attempt to open filename.
FILE *fp = fopen(filename, "r");
if (!fp) return false; // Return false upon failure.
// Try to read one line. If you have more, you need a while loop.
char imposta_tratt[300];
if (!fgets(imposta_tratt, sizeof imposta_tratt, fp)) {
fclose(fp);
return false;
}
*tsize = 0;
char tmp[300]; // Temporary buffer. Used for conversion into int.
char *token = strtok(imposta_tratt, delim);
while (token && *tsize < tsizemax) {
strncpy(tmp, token, sizeof tmp);
tratt[(*tsize)++] = atoi(tmp);
token = strtok(NULL, delim);
}
fclose(fp);
return true;
}
const char *filename: The file you want to parse.
const size_t tsizemax: The maximum size of your tratt array. It is important to control the size, otherwise your code will have buffer overflow (think of when your file has more than 100 tokens, for example).
int tratt[tsizemax]: The array that will hold the values.
size_t *tsize: The number of tokens read (used in combination of tsizemax).
const char *delim: The delimiter(s), in your case a ,.
This is your main():
int main(void)
{
int tratt[100];
size_t size = 0;
if (!read_file_content("in.txt", 100, tratt, &size, ",")) {
puts("Failed");
return 1;
}
for (size_t i = 0; i < size; ++i)
printf("%d\n", tratt[i]);
}
Output:
0
30
25
10
Suppose "in.txt" has contents
0,30,25,10
The below program uses fscanf to read the integers into the tratt array, one-by-one. As we read integers using fscanf, we make sure it's return value is as expected. If not, we close the file and exit. In the event that the return value of fscanf is not as expected, the program also prints which type of error occurred. Currently, if any error occurs, the program stops. However, you can make the program behave differently depending on the error that occurred if you like.
As output, the program prints all of the integers read into the tratt array. The output is
0
30
25
10
Now this program assumes we know the number of elements we want to read into tratt. If we do not, we could allow for dynamically allocating more memory should the array need more elements or perhaps "in.txt" could contain a data structure, say, at the beginning/end of the file that records information about the file, such as the number of numbers in the file and the data type (a binary file would be best suited for this). These are just a couple of the possibilities.
A better approach might be to read characters in one-by-one (say, using getc) and use strtol to convert a sequence of character digits to a long int (I would have taken an approach similar to this).
Nevertheless, this approach is more succinct and should suffice.
#include <stdio.h>
#include <stdlib.h>
#define FILE_NAME "in.txt"
#define MAX_LEN 4
int main(void) {
int i, tratt[MAX_LEN];
FILE *fp = fopen(FILE_NAME, "r"); /* open file for reading */
/* if cannot open file */
if (fp == NULL) {
printf("Cannot open %s\n", FILE_NAME);
exit(EXIT_FAILURE);
}
/* read integer, checking return value of scanf as expected */
if (fscanf(fp, "%d", &tratt[0]) != 1) {
if (ferror(fp))
printf("fscanf: read error\n");
else if (feof(fp))
printf("fscanf: end of file\n");
else
printf("fscanf: matching failure\n");
fclose(fp);
exit(EXIT_FAILURE);
}
for (i = 1; i < MAX_LEN; i++)
/* read comma plus integer, checking return value of scanf */
if (fscanf(fp, ",%d", &tratt[i]) != 1) {
if (ferror(fp))
printf("fscanf: read error\n");
else if (feof(fp))
printf("fscanf: end of file\n");
else
printf("fscanf: matching failure\n");
fclose(fp);
exit(EXIT_FAILURE);
}
fclose(fp); /* close file */
/* print integers stored in tratt */
for (i = 0; i < MAX_LEN; i++)
printf("%d\n", tratt[i]);
return 0;
}
I have an array (POINTS) with a length >20M of the following structure (point) and would like to save it in a binary file to read it afterwards in a different program:
typedef struct {
char *name;
unsigned char namelength;
} point;
if((POINTS = (point *) malloc (N * sizeof(point))) == NULL){
printf("when allocating memory for the points vector\n");
exit(0);
}
What I'm doing is the following; First I'm creating a variable namestot to know how many characters I have in total (some names may be empty):
for (i = 0; i < N; i++) namestot += POINTS[i].namelength;
Then I'm writing the array in a file:
if ((fin = fopen(name, "wb")) == NULL){
printf("the output binary data file cannot be open\n");
exit(0);
}
for ( i=0; i < N; i++){
if (POINTS[i].namelength){
if( fwrite(point[i].name, sizeof(char), POINTS[i].namelength, fin) != POINTS[i].namelength){
printf("when writing names to the output binary data file\n");
exit(0);
}
}
}
With that I create the file without issues. Now we change to another program with the binary file saved, so we open and read it:
if ((fin = fopen (argv[1], "r")) == NULL){
printf("the data file does not exist or cannot be opened\n");
exit(0);
}
//Here we allocate memory again for the POINTS vector
if((POINTS = (point *) malloc (N * sizeof(point))) == NULL){
printf("when allocating memory for the points vector\n");
exit(0);
}
if((allnames = (char *) malloc (namestot * sizeof(char))) == NULL){
printf("when allocating memory for the names vector");
exit(0);
}
if (fread(allnames, sizeof(char), namestot, fin) != namestot){
printf("when reading names from the binary data file\n");
exit(0);
}
//Setting pointers to names
for (i = 0; i < N; i++){
if(POINTS[i].namelength > 0){
POINTS[i].name = allnames;
allnames += POINTS[i].namelength;
}
}
However, when I try to read the first non-empty name the program prints the entire array of names, any advice on how to set the pointers to the mesan to have the POINTS array as I had it in the first program?
Thanks!
PS: if there's any non-declared variable I've probably forgot to paste it here, that's not the issue.
You are writing variable length strings to files, so when you read it you need to know length of individual string
You may decide to include length string along with the string to write in the file or ensure you write trailing '\0' to indicate earlier string ends and new one begins from next byte, your reader program will have to parse the strings accordngly
prints the entire array of names
Sounds like because you do not tell your program the end of each name, print char * stop when meet a \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'm working on steganography program in Java. But I got advice that I be able to resolve this task better in C program. I would like to try it, but I'm pretty bad in C programing. For now I would like to read one gif file and find byte which is used as image separator (0x2c from GIF format).
I tried to write this program:
int main(int argc, char *argv[])
{
FILE *fileptr;
char *buffer;
long filelen = 0;
fileptr = fopen("D:/test.gif", "rb"); // Open the file in binary mode
fseek(fileptr, 0, SEEK_END); // Jump to the end of the file
filelen = ftell(fileptr); // Get the current byte offset in the file
rewind(fileptr); // Jump back to the beginning of the file
buffer = (char *)malloc((filelen+1)*sizeof(char)); // Enough memory for file + \0
fread(buffer, filelen, 1, fileptr); // Read in the entire file
fclose(fileptr); // Close the file
int i = 0;
for(i = 0; buffer[ i ]; i++)
{
if(buffer[i] == 0x2c)
{
printf("Next image");
}
}
return 0;
}
Could someone give me advice how to repair my loop?
Could someone give me advice how to repair my loop?
Option 1: Don't depend on the terminating null character.
for(i = 0; i < filelen; i++)
{
if(buffer[i] == 0x2c)
{
printf("Next image");
}
}
Option 2: Add the terminating null character before relying on it. This is potentially unreliable since you are reading a binary file that could have embedded null characters in it.
buffer[filelen] = '\0';
for(i = 0; buffer[ i ]; i++)
{
if(buffer[i] == 0x2c)
{
printf("Next image");
}
}
Similar to the 'for()' based answer, if you only need to check for a specific byte (0x2c), you can simply do something like the following (and not worry about null in the byte stream), using while().
i = 0;
while(i < filelen)
{
if(buffer[i++] == 0x2c)
{
printf("Next image");
}
}
Really struggling here and cannot figure out how to get my value's from an array.
I first declare this array which I want to hold a set of numbers. IDK why the size is 64, I simply am frustrated and gave it a size.
char *numberList1[64];
I then read in a file using some code I found.
FILE * fp;
char * line = NULL;
size_t len = 0;
ssize_t read;
char string[100];
int counter = 0;
printf("\n\nEnter name of File 1: ");
scanf("%s", string);
fp = fopen(string, "r");
if (fp == NULL) {
printf("invalid filename of %s",string);
exit(EXIT_FAILURE);
}
while ((read = getline(&line, &len, fp)) != -1) {
numberList1[counter] = line;
counter++;
}
Now if were to say something like printf("%s",numberList1[counter]); within the while, I would get all my numbers back.
However when I say the following, I only get the last item printed out however times there are numbers. (vectorLength).
int j;
//vectorLength is the user-entered # of lines/numbers in the file.
for (j = 0; j < vectorLength; j++) {
printf("Writing out: %s \n", numberList1[j] );
//write(pipe1[WRITE], currentNum, bitSize+1);
}
i.e. If I had numbers, 1, 2, 3, 4
I would get: 4 4 4 4
What am I doing wrong??? I have tried to find guides on understanding pointers and arrays in C but I cannot figure it out...
You're not preparing the parameters sent to getline() properly. According to the documentation:
If *lineptr is set to NULL and *n is set 0 before the call, then getline() will allocate a buffer for storing the line. This buffer should be freed by the user program even if getline() failed.
You want a new line buffer for each line, and you at-least-seem to want getline() to make that for you, so, after each successful read, and once you save the returned buffer pointer allocated by getline() in your array, clear the line pointer back to NULL and the length parameter back to zero:
char * line = NULL;
size_t len = 0;
while ((read = getline(&line, &len, fp)) != -1 && counter < 64)
{
numberList1[counter++] = line;
line = NULL; // <<==== ADDED
len = 0; // <<==== ADDED
}
free(line); // note: this is here because, though getline() failed, the
// documentation for the api mandates its presence.
I believe I've found the root of the problem.
In the code below, you are reading each line into memory at the location pointed to by line. You are then storing the pointer to the memory into each index in the array. The problem is that you are overwriting the memory at the location pointed to by line each time you read in a line. As a result, only the last-read value is stored at that location. Since each index in the array points to the same location, each iteration of the final loop in your code will display the same value.
char * line = NULL;
while ((read = getline(&line, &len, fp)) != -1) {
numberList1[counter] = line; // You are storing the pointer here, NOT the value
counter++;
}
Instead, allocate memory for the array (getline does this automatically) at each iteration of the loop and copy that pointer into the array.
while ((read = getline(&line, &len, fp)) != -1) {
numberList1[counter] = line;
line = NULL;
counter++;
}
Make sure to free all memory allocated during this process.