Dynamic memory and pointers arguments - c

I have this two functions, meant to do the same thing - read every line from a file with only integers and store them on an array:
I call them like this on the main() function:
StoreinArray1(X, size, f);
StoreinArray2(X, size, f);
The First works but the Second doesn't.
First
int StoreinArray1(int X[], int *size, char *file)
{
int i=0;
FILE *f;
f = fopen(file, "r");
X = (int*) realloc (X, *size * sizeof(int));
for (i=0;i<*size;i++)
{
fscanf(f, "%d", &X[i]);
}
return 1;
}
Second
int StoreinArray2(int X[], int *size, char *file)
{
FILE *f;
f = fopen(file, "r");
if (f == NULL)
return -1; // failed opening
*size = 0;
while (!feof(f))
{
if (fscanf(f, "%d", &X[*size]) == 1)
*size = *size + 1;
}
fclose(f);
return 1;
}
For the First I used dynamic memory allocation and actually calculated size:
X = malloc(0);
while ((ch = fgetc(f)) != EOF)
{
if (ch == '\n')
lines++;
}
size = &lines;
For the Second I can't do the same. Visual Studio Code crashes when I try.
So I tried to do *size = 0 and then StoreinArray2(X, size, f); but it didn't work either.
So my question is about the second function:
Is it calculating the size while it is scanning the file? Supposedly it isn't necessary to use dynamic memory allocation (my teacher said).
If so then how can I pass some "size" argument correctly? As a pointer or just a simple integer?
Thank you in advance!
Edit:
Here is the full First program:
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *f;
int *size=0, *X, lines=1;
char *file = {"file.txt"};
char ch;
X = malloc(0);
f = fopen(file, "r");
while ((ch = fgetc(f)) != EOF)
{
if (ch == '\n')
lines++;
}
size = &lines;
StoreinArray(X, size, file);
}
int StoreinArray(int X[], int *size, char *file)
{
int i=0;
FILE *f;
f = fopen(file, "r");
X = (int*) realloc (X, *size * sizeof(int));
for (i=0;i<*size;i++)
{
fscanf(f, "%d", &X[i]);
}
for (i=0;i<*size;i++)
printf("%d\n",X[i]);
return 1;
}
And the Second:
int main()
{
int X[100];
int *size;
char *file = {"file.txt"};
*size = 0;
StoreinArray(X, size, file);
}
int StoreinArray(int X[], int *size, char *file)
{
FILE *f;
f = fopen(file, "r");
if (f == NULL)
return -1;
*size = 0;
while (!feof(f))
{
if (fscanf(f, "%d", &X[*size]) == 1)
*size = *size + 1;
}
fclose(f);
return 1;
}
In first I had to open the file in main to count the number of lines. I know I forgot fclose(f) and free(X) in main, but with those instructions VSC crashes.
int StoreinArray (int X[], int *size, char *file)
{
FILE *f;
int i=0;
f = fopen(file, "r");
if (f == NULL)
return -1;
*size = 0;
while (!feof(f))
{
if (fscanf(f, "%d", &X[*size]) == 1)
{
*size = *size + 1;
X = (int *) realloc (X , *size * sizeof(int));
}
}
fclose(f);
return 1;
}
int main()
{
int *X, size=0;
char *file = {"f.txt"};
X=malloc(0);
StoreinArray(X, &size, file);
free(X);
}

The problem with the second version of your program is the declaration of size in main. Declare it as an int, not a pointer to an int. Your current program is crashing because you didn't allocate any space for size, and when StoreInArray tried to update it, you got an access violation. So, main should look like this:
int main()
{
int X[100];
int size;
char *file = {"file.txt"};
size = 0;
StoreinArray(X, &size, file);
}

OK, I'll try to be through about it and explain all the things I can find.
First of all, we need to talk about variables, pointers and memory, because it seems that you don't have a very firm grasp of these concepts. Once that clicks, the rest should follow easily.
First up, simple variables. That part is easy, I think you more or less understand that.
int x; // This is an integer variable. It's not initialized, so its value could be anything
int meaning = 42; // This is another integer variable. Its value will be 42.
double pi = 3.14; // A variable with digits after the decimal point
char c = 15; // Another inte... well, yes, actually, char is also an integer.
char c2 = 'a'; // Nice, this also counts. It's converted to an integer behind the scenes.
Etc.
Similarly with arrays:
int arr[10]; // Array with 10 values. Uninitialized, so they contain garbage.
int arr2[3] = { 1, 2, 3 }; // Array with 3 values, all initialized
int arr3[] = {1, 2, 3, 4, 5}; // Array with 5 values.
Arrays are basically just a bunch of variables created at once. When you make an array, C needs to know the size, and the size must be a fixed number - you can't use another variable. There's a reason for this, but it's technical and I won't go into that.
Now about memory. Each of these variables will be stored somewhere in your computer's RAM. The precise location is unpredictable and can vary each time you run your program.
Now, RAM is like a huuuge array of bytes. There's byte number 0, byte number 1, etc. An int variable takes up 4 bytes, so it could, for example, end up in bytes number 120, 121, 122 and 123.
All the bytes in a single variable (or in a single array) will be next to each other in RAM. Two different variables could end up in the opposite ends of your RAM, but the bytes in each of those variables will be together.
Now we come to the concept of a pointer. A pointer is basically just an integer variable. It contains the RAM-number of the first byte of some other variable. Let's look at an example:
int i = 42;
int *p = &i;
Suppose that the variable i got stored in the bytes number 200...203 (that's 4 bytes). In those bytes we have the value 42. Then let's suppose that the variable p got stored in the bytes number 300...303 (that's another 4 bytes). Well, these 4 bytes will contain the value 200, because that's the first byte of the i variable.
This is also what programmers mean when they say "(memory) address of <variable>" or "a pointer to <variable>. It's the number of the first byte in RAM of <variable>. Since all bytes of the same variable stick together, then by knowing the first byte (and knowing the type of the variable), you can figure out where the rest of <variable> is in memory.
Now let's add one more line in our example:
*p = 5;
What the computer does in this case is it takes the address which was stored in p, goes to that location in memory, treats the following 4 bytes as an integer, and puts the value 5 there. Since we had previously set p to "point" at the address of i, this has the same effect as simply setting the i variable itself.
Ok, did you get all of this? This is a bit tricky and usually takes a while to wrap your head around it. Feel free to re-read it as many times as necessary to understand it. You'll need it to move on.
Ready? Ok, let's talk a bit about stack and dynamic memory.
When the program starts, the OS automatically allocates a bit of memory for it, just to make it easier for it to start. It's like a big array of bytes, all together in memory. Nowadays it's usually about 1MB, but it can vary. This memory is called "The Stack". Why is it called that? Eh, I'll explain some other time.
Anyways, When your main() function starts, the OS goes like "Here you go my good fellow, a pointer to The Stack. It's all yours to use as you see fit! Have a nice day!"
And your main() function then uses it to store all the variables you make in it. So when you go like p = &i; then the address you get stored in p is somewhere within The Stack.
Now when main() calls another function, such as StoreinArray(), it also gives it a pointer to the stack and says "OK, here's a pointer to the stack. Careful, I've already used the first XXX bytes of it, but feel free to use the rest".
And then StoreinArray() uses the stack to put its variables there. And when StoreinArray() calls something else, it does the same, and on and on.
Now, there are a few things to note here:
This scheme is nice, because nobody needs to "allocate" or "deallocate" any memory. It's easier, it's faster.
However, when a function returns, all its variables are considered to be gone and that memory is fair game to anyone else later wanting it. So be careful about pointers pointing to it. They will only be valid while the function is running. When it returns - well, the pointer will still "work", but who knows when something will overwrite that memory... And if you write to that memory, who can tell what you will mess up? Many subtle bugs have been created this way.
The stack is fairly limited and can be exhausted. When all bytes in it are used up, your program WILL crash. The typical way this happens is either when you try to create a very large array, or you go into some sort of infinite loop where the function keeps calling itself over and over again. Try that. :)
So, for these cases you use "dynamic" memory. In C that mostly means malloc(). You tell malloc() how many bytes of memory you need, and malloc() finds a large enough unclaimed space in the RAM, marks it as used, and gives you a pointer to it. Well, that's a simplified view of things anyway.
The same approach works when you don't know beforehand how much memory you will need.
The downside is that you need to free() the memory when you're done with it, or you may run out of available memory, and then malloc() will fail. Be also aware that after you've freed the memory, all pointers to it should be considered invalid, because you're not the owner of that particular piece of memory anymore. Anything can happen if you keep messing with it.
Phew, that's a lot. OK, I need a break. I'll come back and analyze your programs a bit later. But if you've understood all of this, you should now be able to spot the mistakes in your programs. Try going through them, line by line, and narrating to yourself what each line does.
Many, many hours later:
OK, so let's take a look at your programs. The first one:
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *f;
int *size=0, *X, lines=1;
char *file = {"file.txt"};
char ch;
X = malloc(0);
f = fopen(file, "r");
while ((ch = fgetc(f)) != EOF)
{
if (ch == '\n')
lines++;
}
size = &lines;
StoreinArray(X, size, file);
}
int StoreinArray(int X[], int *size, char *file)
{
int i=0;
FILE *f;
f = fopen(file, "r");
X = (int*) realloc (X, *size * sizeof(int));
for (i=0;i<*size;i++)
{
fscanf(f, "%d", &X[i]);
}
for (i=0;i<*size;i++)
printf("%d\n",X[i]);
return 1;
}
There are two things that can be improved here. First - the size and lines variables. There's no need for both of them. Especially since you set size to point to lines anyway. Just keep lines and all will be fine. When you pass it to StoreinArray(), pass it as a simple integer. There's no need for a pointer.
Second, the X array. You're doing something odd with it and it seems like you're fumbling in the dark. There's no need for the malloc(0) and then later realloc(X, *size*sizeof(int). Keep it simple - first count the lines, then allocate the memory (as much as needed). Also, keep the memory allocation in the main() method and just pass the final X to the StoreinArray. This way you can avoid another subtle bug - when inside the StoreinArray() function you execute the line X = (int*) realloc (X, *size * sizeof(int)); the value of X changes only inside the StoreinArray() function. When the function returns, the variable X in the main() function will still have its old value. You probably tried to work around this with the reallocate() dance, but that's not how it works. Even worse - after the realloc(), whatever value the X used to be, isn't a valid pointer anymore, because realloc() freed that old memory! If you had later tried to do anything with the X variable in the main() function, your program would have crashed.
Let's see how your program would look with the changes I proposed (plus a few more small cosmetic tweaks):
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *file = "file.txt";
FILE *f = fopen(file, "r");
int *X, lines=1;
char ch;
while ((ch = fgetc(f)) != EOF)
{
if (ch == '\n')
lines++;
}
fclose(f);
X = (int *)malloc(lines * sizeof(int));
StoreinArray(X, lines, file);
}
void StoreinArray(int X[], int lines, char *file)
{
int i=0;
FILE *f = fopen(file, "r");
for (i=0;i<lines;i++)
{
fscanf(f, "%d", &X[i]);
}
fclose(f);
for (i=0;i<lines;i++)
printf("%d\n",X[i]);
}
OK, now the second program.
int main()
{
int X[100];
int *size;
char *file = {"file.txt"};
*size = 0;
StoreinArray(X, size, file);
}
int StoreinArray(int X[], int *size, char *file)
{
FILE *f;
f = fopen(file, "r");
if (f == NULL)
return -1;
*size = 0;
while (!feof(f))
{
if (fscanf(f, "%d", &X[*size]) == 1)
*size++;
}
fclose(f);
return 1;
}
Right off the bat, the size variable will crash your program. It's a pointer that isn't initialized so it points to some random place in memory. When a little lower you try to write to the memory it points to (*size = 0), that will crash, because most likely you won't own that memory. Again, you really don't need a pointer here. In fact, you don't need the variable at all. If you need to know in the main program how many integers the StoreinArray() read, you can simply have it return it.
There's another subtle problem - since the size of X array is fixed, you cannot afford to read more than 100 integers from the file. If you do, you will go outside the array and your program will crash. Or worse - it won't crash, but you'll be overwriting the memory that belongs to some other variable. Weird things will happen. C is lenient, it doesn't check if you're going outside the allowed bounds - but if you do, all bets are off. I've spent many hours trying to find the cause of a program behaving weirdly, only to find out that some other code in some completely unrelated place had gone outside its array and wreaked havoc upon my variablers. This is VERY difficult to debug. Be VERY, VERY careful with loops and arrays in C.
In fact, this kind of bug - going outside an array - has it's own name: a "Buffer Overrun". It's a very common security exploit too. Many security vulnerabilities in large, popular programs are exactly this problem.
So, the best practice would be to tell StoreinArray() that it can store at most 100 integers in the X array. Let's do that:
#include <stdio.h>
#include <stdlib.h>
#define MAX_X 100
int main()
{
int X[MAX_X];
char *file = "file.txt";
int lines;
lines = StoreinArray(X, MAX_X, file);
}
int StoreinArray(int X[], int maxLines, char *file)
{
FILE *f;
int lines;
f = fopen(file, "r");
if (f == NULL)
return -1;
while (!feof(f))
{
if (fscanf(f, "%d", &X[lines]) == 1)
lines++;
if (lines == maxLines)
break;
}
fclose(f);
return lines;
}
So, there you are. This should work. Any more questions? :)

Related

how do I assign individual string to an element in one array of pointer?

I am new to C and still trying to figure out pointer.
So here is a task I am stuck in: I would like to assign 10 fruit names to a pointer of array and print them out one by one. Below is my code;
#include <stdio.h>
#include <string.h>
int main(){
char *arr_of_ptrs[10];
char buffer[20];
int i;
for (i=0;i<10;i++){
printf("Please type in a fruit name:");
fgets(buffer,20,stdin);
arr_of_ptrs[i]= *buffer;
}
int j;
for (j=0;j<10;j++){
printf("%s",*(arr_of_ptrs+j));
}
}
However after execution this, it only shows me the last result for all 10 responses. I tried to consult similar questions others asked but no luck.
My understanding is that
1) pointer of array has been allocated memory with [10] so malloc() is not needed.
2) buffer stores the pointer to each individual answer therefore I dereference it and assign it to the arr_of_ptrs[i]
I am unsure if arr_of_ptrs[i] gets me a pointer or a value. I thought it is definitely a pointer but I deference it with * the code and assign it to *buffer, program would get stuck.
If someone could point out my problem that would be great.
Thanks in advance
Three erros, 1. You must allocate memory for elements of elements of arr_of_ptrs, now you only allocate the memory for elements of arr_of_ptrs on stack memory. 2. arr_of_ptrs[i]= *buffer; means all of the arr_of_ptrs elements are pointed to same memory address, which is the "buffer" pointer. So all the elements of arr_of_ptrs will be same to the last stdin input string. 3. subsequent fgets() call has potential problem, one of the explaination could be here
A quick fix could be,
#include <stdio.h>
#include <string.h>
int main(){
const int ARR_SIZE = 10, BUFFER_SIZE = 20;
char arr_of_ptrs[ARR_SIZE][BUFFER_SIZE];
char *pos;
int i, c;
for (i = 0; i < ARR_SIZE; ++i) {
printf ("Please type in a fruit name: ");
if (fgets (arr_of_ptrs[i], BUFFER_SIZE, stdin) == NULL) return -1;
if ((pos = strchr(arr_of_ptrs[i], '\n')))
*pos = 0;
else
while ((c = getchar()) != '\n' && c != EOF) {}
}
for (i = 0; i < ARR_SIZE; ++i)
printf("%s\n", arr_of_ptrs[i]);
return 0;
}
The misunderstanding is probably that "Dereferencing" an array of characters, unlike dereferencing a pointer to a primitive data type, does not create a copy of that array. Arrays cannot be copied using assignment operator =; There a separate functions for copying arrays (especially for 0-terminated arrays of char aka c-strings, and for allocating memory needed for the copy):
Compare a pointer to a primitive data type like int:
int x = 10;
int *ptr_x = &x;
int copy_of_x = *ptr_x; // dereferences a pointer to x, yielding the integer value 10
However:
char x[20] = "some text"; // array of characters, not a single character!
char *ptr_x = &x[0]; // pointer to the first element of x
char copy_of_first_char_of_x = *ptr_x; // copies the 's', not the entire string
Use:
char x[20] = "some text";
char *ptr_x = &x[0];
char *copy_of_x = malloc(strlen(ptr_x)+1); // allocate memory large enough to store the copy
strcpy(copy_of_x,ptr_x); // copy the string.
printf("%s",copy_of_x);
Output:
some text

Segmentation Error in C code when i try to read the hex file

Im trying to read a hex file, i have partitioned my code into two parts, load file data to buffer and second part access the buffer to read specific region data. The compilation is clean but when i run test, it throws segmentation fault
#include
#include
#include
char *fip_buffer;
char *emmc_pattern_buffer;
char hex_pattern() {
FILE *fileptr;
char *buffer;
long filelen;
int i,j;
fileptr = fopen("fip.hex", "rb");
if( fileptr == NULL ) {
printf("cannot open file");// exit(1);
}
fseek(fileptr, 0, SEEK_END);
filelen = ftell(fileptr);
rewind(fileptr);
fip_buffer = (char *)malloc((filelen+1)*sizeof(char));
for(i = 0; i < filelen; i++) {
fread(fip_buffer+i, 1, 1, fileptr);
}
fclose(fileptr); // Close the file
return(fip_buffer);
}
char hex_pattern_read(int a, int filelen){
char mem[8],mem2[7];
int i,j;
for(i=a;i<filelen;i++){
mem[j]=fip_buffer[i];
mem[8]='\0';
j++;
if(j==8){strcpy(mem2,mem);j=0; break;
}
}
emmc_pattern_buffer=mem2;
return(emmc_pattern_buffer);
}
int main(int argc, char **argv) {
printf("Reading hex file");
int i,j;
hex_pattern();
int len = strlen(fip_buffer);
printf("size of buffer is=%d\n%s\n",len,fip_buffer);
for(i=0; i<2; i++){
// printf("Entered loop1");
for(j=0;j<3;j++){
int temp = (j*8)+(128*i);
hex_pattern_read(temp,len);
printf("%s\n",emmc_pattern_buffer);
}
}
return 0;
}
First thing to say, since mem2 is declared by:
char mem[8],mem2[7];
is, that you attempt to return a pointer to char with:
return(mem2);
as opposed to what it is declared in the definition of hex_pattern() as return type; a value of type int:
int hex_pattern(int a) {}
While this on its own may cause the NULL pointer for itself (presume the compiler would let it pass with a warning at least), You even get NULL if you would declare/define hex_pattern() the right way with:
char* hex_pattern (int a){}
mem2 is a pointer to the first element of the local char array of mem2[], but the array of mem2[]is not existing anymore after you will leave hex_pattern() back to the caller, here main().
The array of mem2[]is of storage class auto by default (when you omitting a specific storage class) and an object of that storage class is only alive in the function it was defined/declared. It is determined when leaving the function scope.
So, the pointer points back to NULL, because at the address the pointer is pointing to, is no longer a valid object with a valid value stored.
If you really want to return the whole array of mem2[], which isn´t possible on its own, you can find good alternatives best explained here: Returning an array using C
Also you should never incorporate statements after return, like you did it with:
return(mem2);
fclose(fileptr); // Close the file
Simply because of the reason that these statements do not get executed. return is the final statement. Everything what comes thereafter is ignored.

Accessing values from user-defined functions

I've got a (I think) pretty easy question that I need help with. I'm working on learning pointers with called user-defined functions in C.
I've got two functions, my main() and another which pulls certain data from a file, read_file(). Read_file() pulls data from a specified file - an integer, (coeff_num) and a series of values (coeff_values) - and prints out the data. Then main() is meant to reprint this data as a check, to ensure that it's being called correctly in order to perform further calculations.
My problem is this: everything is printing out fine in the read_file() function. While checking in main(), data_num is printing out fine, but data_values isn't.
The code (with some irrelevant bits edited out, mainly error checking stuff) is as follows:
int read_file(int *data_num, double **data_values, char *filename);
int main()
{
int data_num;
double **data_values;
char *filename[] = {/*FILES*/};
read_fule(&data_num, data_values, *filename);
printf("Check Number:\n%u\n", data_num);
printf("Check Values:\n);
for(int i = 0; i<data_num; i++)
{
printf("%u\t", data_values[i]);
}
return(0);
}
and:
int read_file(int *data_num, double **data_values, char *filename)
{
FILE * fp = fopen(filename, "rb"); //Opening file
/* Error checking code here - see if file opens, find length
return if not long enough, etc */
//Find number of values
char buffer_n[4];
fread(buffer_n, 4, 1, fp);
int result = buffer_n[0]|(buffer_n[1] << 8)|(buffer_n[2] << 16)|(buffer_n[3] << 24); //Change endian
*data_num = result;
/* Instructed to allocate memory */
data_values = malloc(8*result); //Allocating memory
//Reads data values
fread(data_values, 8, result, fp);
//Prints results as float
printf("Number of data values: %d \n", result);
for(int i=0; i<result; i++)
{
printf("%0.3f\t", data_values[i]);
}
fclose(fp);
return 1;
}
I'm fairly certain that this is an issue with my pointers. For the program, I have to use malloc() when reading data_values, and read_file has to have the prototype of: int read_file(int *data_num, double **data_values, char *filename). Can someone give me some guidance about where I've messed up?
Cheers for any help, it'd be greatly appreciated.
I set result = 30 as you told me, changed a few places, and I think now it works fine.
I think you don't need double** pointer, what you need is double* pointer.
And you need cast the void* to double*:
data_values = (double*)malloc(8*result); //Allocating memory
This code works fine:
//data_values should be defined as double*
int read_file(int *data_num, double *data_values, char *filename)
{
FILE * fp = fopen(filename, "rb"); //Opening file
/* Error checking code here - see if file opens, find length
return if not long enough, etc */
//Find number of values
char buffer_n[4];
size_t i;//added
fread(buffer_n, 4, 1, fp);
//int result = buffer_n[0]|(buffer_n[1] << 8)|(buffer_n[2] << 16)|(buffer_n[3] << 24); //Change endian
int result = 30;
*data_num = result;
/* Instructed to allocate memory */
data_values = (double*)malloc(8*result); //Allocating memory
//Reads data values
fread(data_values, 8, result, fp);
//Prints results as float
printf("Number of data values: %d \n", result);
for(int i=0; i<result; i++)
{
printf("%0.3f\t", data_values[i]);
}
fclose(fp);
return 1;
}
Edit:
If you want to use double**, you can try this solution:
/* Instructed to allocate memory */
data_values[0] = (double*)malloc(8 * result); //Allocating memory
//Reads data values
fread(data_values[0], 8, result, fp);
//Prints results as float
printf("Number of data values: %d \n", result);
for(int i=0; i<result; i++)
{
printf("%0.3f\t", data_values[0][i]);
}
But you have to notice that this is not a form, this is still used as an array, so you may change it later according to your situation.

How to load data from file into float* in C

I have an ASCII file in which the entries of a vector are stored. I do not know the length (number of rows) of the file, nor do I have an estimation about its size as it may strongly vary from a few lines to some tens of thousands. I need an efficient way to read the data stored in that file and load them to a float* variable. The code should be in C.
My question is how to allocate memory for the vector which I need to create given that I do not know its size beforehand? Can you please give an example?
Finally, what is in your opinion the most appropriate prototype for such a function? Should it be something like:
load_data(const char* filename, float* data, int* vector_size);
?
Update 1.: While doing some initial tests, I wrote the following code:
void create_random_matrix(float* matrix, const int nrows) {
matrix = (float *) malloc(sizeof (float) * nrows);
short i;
for (i = 0; i < nrows; i++) {
matrix[i] = 7.0f;
}
}
which should return an array with all its elements equal to 7.0f. Instead, when I call it from my main.c:
float *a;
create_random_matrix(a, 10);
printf("%f",a[0]);
it prints 0.0f. How is that possible?!
Update 2. Was it not for your help, the following (working) code wouldn't have been written:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#define LINE_SIZE 10
#define ALLOCATION_CHUNK 50
int load_vector_data(const char* filename, float** vector, int* length) {
*vector = malloc(sizeof (float) * ALLOCATION_CHUNK);
int allocated_rows = ALLOCATION_CHUNK;
u_short i = 0;
FILE* fr = fopen(filename, "r");
if (fr == NULL) {
exit(FILE_NOT_FOUND);
}
char line[LINE_SIZE];
while (fgets(line, LINE_SIZE, fr) != NULL) {
if (i >= allocated_rows){
allocated_rows += ALLOCATION_CHUNK;
*vector = realloc(*vector, sizeof (float) * allocated_rows);
}
strip_newline(&line, LINE_SIZE);
(*vector)[i] = strtod(line, (char **) NULL);
i++;
}
*length = i;
*vector = realloc(*vector, sizeof (float) * i);
fclose(fr);
}
void strip_newline(char *str, int size) {
u_short i;
for (i = 0; i < size; ++i) {
if (str[i] == '\n') {
str[i] = '\0';
return;
}
}
}
I tried it with an 8000-lines file and seems to be working just fine! Please, feel free to comment.
fgets is you friend for reading the data from the file (If my assumption that each bit of data is on a new-line is correct). Read each line in 1 by 1 and use an strtof on the text you read. Reading text and converting to floats is inherently a slow process so I reckon the above is perfectly good enough.
As for your second question there are a couple of ways to do it. You could pass a float** in and make the malloc inside the function. Though this has the disadvantage of you needing to free it outside the function which is not exactly obvious. The only other way, i can think of, would be to scan through the file and count the number of new-lines then pre-allocate the array length for that.
Its hard to say whether doing a malloc and a bunch of reallocs would be more efficient than the scan through to count the number of lines, it would probably be worth trying both methods (neither is particularly hard) and seeing which one is faster for you.

Reading an array from a file

I am back to C from Java and C#. I am stuck with the following simple program attempting to read two arrays from a file with a function. Can anyone point out where am I messing up?
Compiler says:
error: invalid operands to binary * (have ‘int *’ and ‘int *’)
The file format is
4
1 2 3 4
23 23 14 11
My ReadFromFile function needs to fill buffers A and B from the file.
#include<stdio.h>
void ReadFromFile (const char* file_name, int *A, int *B, int *length)
{
FILE* file = fopen (file_name, "r");
fscanf (file, "%d", length);
int i;
for(i = 0; i < length; i++)
{
fscanf (file, "%d", A+i);
}
for(i = 0; i < length; i++)
{
fscanf (file, "%d", B+i);
}
fclose (file);
}
int main()
{
int *A; int *B; int length;
ReadFromFile("input.txt", A, B, &length);
return 0;
}
void ReadFromFile (const char* file_name, int *A, int *B, int *length)
/* ... */
for(i = 0; i < length; i++)
{
fscanf (file, "%d", A+i);
}
You have passed in a single integer A from main(), but here you are trying to access completely unrelated memory. Same goes for B. Did you mean to allocate A and B as arrays?
e.g. change:
int *A; int *B; int length;
to
int A[100], B[100], length;
or something similar. (Perhaps dynamically allocate the arrays once you know how many you need -- or allocate them with malloc(3) and grow them with realloc(3) if you need to.)
int main()
{
int A; int B; int length;
ReadFromFile("input.txt", &A, &B, &length);
return 0;
}
Try using A and B as variables not pointers and call the function with the addresses.
I'm not sure if thats the Issue. But give it a try.
Sorry I was confused by the int pointers. I guess what you want is int[] A what is in fact the same as int* A. But then you have to allocate some memory for the array or initialize it with a given size.
First of all A and B are pointers to junk, you need to allocate space if you actually want to store something (or expect a Segmentation fault or memory corruption).
It's complaining about your for loops. length is never initialized so you're sending a pointer to junk data anyway (or it's never populated in read from file).
i < length isn't valid (in that sense) because you're comparing an int value to an address or int * (which doesn't make sense). You might mean i < *length; because length is a pointer and needs to be dereferenced for its actual value.
When calling your function you should give an address reference e.g. &A and &B
And this is how you should read a text file appropriately :)
FILE *file = fopen(file_name, "r");
while(file != EOF){
fscanf(...)
}
EDIT:
You don't need to use double pointers. Simply initialize in main() integers Int A,B and give your method them addresses.
In your function you use A+i that accesses places in memory not allocated by you.
In other words: you need a call to malloc first to get the memory.
Think about your structure here:
You have address variables A and B but you never pointed them to the address of allocated memory. If you want to do this BEFORE your function you need to know the length of the array. If you want to do it IN your function, you need to pass the address of A and B to assign to it:
void ReadFromFile (const char* file_name, int** A, int** B, int* length)
{
FILE* file = fopen (file_name, "r");
fscanf (file, "%d", length);
*A = (int*) malloc(length * sizeof(int))
// now use (*A)+i
You would then change main
int* A; int* B; int length;
ReadFromFile("input.txt", &A, &B, &length);

Resources