I am trying to realloc an array of structs when it runs out of space as I'm putting elements into it but I keep receiving a realloc stderr. The array of struct will eventually have 235,000 elements in it. When I set the initial start size to 100,000 I receive the stderr when trying to realloc. If I se the initial start size to 300,000 it does not give the error because it never reaches the realloc statement.
#define _XOPEN_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#define BUFFERLEN 200
#define START_SIZE 100000
#define GROW 1000
#define TRUE 1
#define FALSE 0
typedef struct{
char *forw;
char *back;
} word;
typedef struct{
char *entry;
} single_words;
FILE *words;
/*-------------Function Prototypes------------*/
void reverse(char* string, char* revstr, int len);
int search_struct(char* find, word* words, int length);
int compare(const void* eventa, const void* eventb);
int length(char* string);
int main(void)
{
char *buffer;
int letter_index[26];
char alpha[] = "abcdefghijklmnopqrstuvwxyz";
int i=0, found = FALSE, strlen=0, letter=0;
word *word_storage;
single_words *output_storage;
int num_words = 0, size = 0;
int num_output = 0, output_size = 0;
/*buffer for the input strings of the words in the input file*/
buffer = (char*) malloc (sizeof(char)*BUFFERLEN);
if(!buffer){
fprintf(stderr, "Error in buffer string mem alloc\n");
exit(1);
}
/*Initializing the array of structs to store the forward and reverse of each word*/
word_storage = (word*) malloc (sizeof(word)*START_SIZE);
if(!word_storage){
fprintf(stderr, "Error in word_storage string mem alloc\n");
exit(1);
}
size = START_SIZE;
/*Initializing the array of structs for the output*/
output_storage = (single_words*) malloc (sizeof(single_words)*START_SIZE);
if(!output_storage){
fprintf(stderr, "Error in output_storage mem alloc\n");
exit(1);
}
output_size = START_SIZE;
/*Set the letter index 0(which is a) to the first character*/
letter_index[0] = 0;
words = fopen("words", "r");
/*Read the words(forward and reverse) in from stdin into the word_storage*/
while(fgets(buffer, BUFFERLEN, words) != NULL){
buffer = strtok(buffer, "\n");
strlen = length(buffer);
if (num_words < size){
/*Allocate memory for the forward and reverse strings*/
word_storage[num_words].forw = (char *) malloc (sizeof(char) * strlen);
if(!word_storage[num_words].forw){
free(word_storage[num_words].forw);
fprintf(stderr, "word_storage forward string malloc was unsuccessful");
exit(1);
}
word_storage[num_words].back = (char *) malloc (sizeof(char) * strlen);
if(!word_storage[num_words].back){
free(word_storage[num_words].back);
fprintf(stderr, "word_storage forward string malloc was unsuccessful");
exit(1);;
}
/*Store the forward and reverse in the strings*/
strncpy(word_storage[num_words].forw, buffer, strlen);
reverse(word_storage[num_words].forw, word_storage[num_words].back, strlen);
printf("%d: %s %s\n", num_words, word_storage[num_words].forw, word_storage[num_words].back);
/*Increment the letter if it changes*/
if(word_storage[num_words].forw[0] != alpha[letter]){
letter++;
letter_index[letter] = num_words + 1;
}
num_words++;
}
else{
/*Increase the size of word_storage*/
word_storage = (word*) realloc (word_storage, sizeof(word) * size * GROW);
if(!word_storage){
free(word_storage);
fprintf(stderr, "Error in word_storage realloc string mem realloc\n");
exit(1);
}
size = size * GROW;
}
}
return 0;
}
The realloc error occurs here:
word_storage = (word*) realloc (word_storage, sizeof(word) * size * GROW);
if(!word_storage){
free(word_storage);
fprintf(stderr, "Error in word_storage realloc string mem realloc\n");
exit(1);
}
size = size * GROW;
So, you initially set size to START_SIZE, which is 100,000. Then when you use that up, you try to allocate sizeof(word) * size * GROW bytes. sizeof(word) is presumably 16 bytes; we know that size is 100000, and GROW is 1000. So that works out to enough space for 100,000,000 entries, of which you say you will use 235,000. That seems like the allocation is a bit on the generous side.
The total space for 100,000,000 entries is 1,600,000,000 bytes. That seems like a lot, although these days many desktop machines could handle that. But it doesn't seem too surprising that realloc fails.
Perhaps you should make GROW something more reasonable, like 2.
By the way, once you've established that word_storage is NULL, there is no point in calling free(word_storage). It does no harm, since free(NULL) is a no-op, but it also does no good for the same reason.
You are multiplying the size by 1000 which is too much (highly exponential growth 1 -> 1000 -> 1000 000 -> 1000 000 000 ...), and you are not displaying the errno. I suggest instead
size_t newsize = 3*size/2 + 1000;
word_storage = realloc(word_storage, sizeof(word)*newsize);
if (!word_storage) {
fprintf(stderr, "Cannot grow storage to %ld size, %s\n",
(long) newsize, strerror(errno));
exit (EXIT_FAILURE);
}
else size = newsize;
then if starting with an initial size of 1000, you are getting the much more reasonable progression 1000 -> 2500 -> 4750 -> 8125 -> 13187 -> 20780 ... and more importantly you are spending at most 50% of useless memory, not a factor of nearly 1000!
Related
I'm working on image convolution for a 416 * 416 color image with a 3 * 3 * 3 * 16 kernal weights (where kernal width - 3, kernal height - 3, filter channels - 3, number of filters - 16). I'm trying to do this in C, but first I need to read the image from the text file and store it in the memory before working with the convolution function. But I think it seems that C doesn't allow me to write 416 * 416 * 3 size string values into an array. I'm actually a newbie to C, so I'm trying to figure out what would be the best approach I should obey in this ?
Below you can see the code.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char line[255];
int fileSize = 416 * 416 * 3;
char image[416 * 416 * 3][255];
FILE *fpointer_1 = fopen("dog_text_image.txt", "r");
for (int i = 0; i < fileSize; i++)
{
fgets(line, 255, fpointer_1);
strcpy(image[i], line);
};
fclose(fpointer_1);
printf("1st value : %s\n", image[0]);
printf("2nd value : %s\n", image[1]);
printf("3rd value : %s\n", image[3]);
return 0;
}
You can alternatively use pointer to array (instead of pointer to pointer) to allocate the entire matrix with a single malloc, and deallocate it with a single free:
#include <stdio.h>
#include <stdlib.h>
int main()
{
/*Pointer to array of length 255*/
char (*image)[255];
/*One malloc to allocate memory*/
if(!(image = malloc(416 * 416 * 3 * sizeof *image))){
perror("Bad allocation!");
return EXIT_FAILURE;
}
/* Do stuff with the matrix*/
image[400][100] = 'a';
/*One free to deallocate memory*/
if(image){
free(image);
}
return 0;
}
It's likely you are getting a stack overflow, try allocating the memory to the heap, something like replacing
char image[416 * 416 * 3][255];
with
//...
char **image;
if(!(image = malloc((fileSize) * sizeof(*image)))){
perror("Bad allocation!");
return EXIT_FAILURE;
}
for(int i = 0; i < fileSize; i++) {
if(!(image[i] = malloc(255))){
perror("Bad allcation!");
return EXIT_FAILURE;
}
}
//...
To free the memory it's the other way around:
for (int i = 0; i < fileSize; i++){
if(image[i])
free(image[i]);
}
if(image)
free(image);
Also, in the code
//...
fgets(line, 255, fpointer_1);
strcpy(image[i], line;
//...
strcpy is really unnecessary you can read directly to image[i] in fgets.
It's possible you can solve the issue with the help of #CraigEstey's comments, try that first.
I am trying to write a simple program that will read words from a file and print the number of occurrences of a particular word passed to it as argument.
For that, I use fscanf to read the words and copy them into an array of strings that is dynamically allocated.
For some reason, I get an error message.
Here is the code for the readFile function:
void readFile(char** buffer, char** argv){
unsigned int i=0;
FILE* file;
file = fopen(argv[1], "r");
do{
buffer = realloc(buffer, sizeof(char*));
buffer[i] = malloc(46);
}while(fscanf(file, "%s", buffer[i++]));
fclose(file);
}
And here is the main function :
int main(int argc, char** argv){
char** buffer = NULL;
readFile(buffer, argv);
printf("%s\n", buffer[0]);
return 0;
}
I get the following error message :
realloc(): invalid next size
Aborted (core dumped)
I have looked at other threads on this topic but none of them seem to be of help. I could not apply whatever I learned there to my problem.
I used a debugger (VS Code with gdb). Data is written successfully into indices 0,1,2,3 of the buffer array but says error : Cannot access memory at address 0xfbad2488 for index 4 and pauses on exception.
Another thread on this topic suggests there might be a wild pointer somewhere. But I don't see one anywhere.
I have spent days trying to figure this out. Any help will be greatly appreciated.
Thanks.
Your algorithm is wrong on many fronts, including:
buffer is passed by-value. Any modifications where buffer = ... is the assignment will mean nothing to the caller. In C, arguments are always pass-by-value (arrays included, but their "value" is a conversion to temporary pointer to first element, so you get a by-ref synonym there whether you want it or not).
Your realloc usage is wrong. It should be expanding based on the iteration of the loop as a count multiplied by the size of a char *. You only have the latter, with no count multiplier. Therefore, you never allocate more than a single char * with that realloc call.
Your loop termination condition is wrong. Your fscanf call should check for the expected number of arguments to be processed, which in your case is 1. Instead, you're looking for any non-zero value, which EOF is going to be when you hit it. Therefore, the loop never terminates.
Your fscanf call is not protected from buffer overflow : You're allocating a static-sized string for each string read, but not limiting the %s format to the static size specified. This is a recipe for buffer-overflow.
No IO functions are ever checked for success/failure : The following APIs could fail, yet you never check that possibility: fopen, fscanf, realloc, malloc. In failing to do so, you're violating Henry Spencer's 6th Commandment for C Programmers : "If a function be advertised to return an error code in the event of difficulties, thou shalt check for that code, yea, even though the checks triple the size of thy code and produce aches in thy typing fingers, for if thou thinkest ``it cannot happen to me'', the gods shall surely punish thee for thy arrogance."
No mechanism for communicating the allocated string count to the caller : The caller of this function is expecting a resulting char**. Assuming you fix the first item in this list, you still have not provided the caller any means of knowing how long that pointer sequence is when readFile returns. An out-parameter and/or a formal structure is a possible solution to this. Or perhaps a terminating NULL pointer to indicate the list is finished.
(Moderate) You never check argc : Instead, you just send argv directly to readFile, and assume the file name will be at argv[1] and always be valid. Don't do that. readFile should take either a FILE* or a single const char * file name, and act accordingly. It would be considerably more robust.
(Minor) : Extra allocation : Even fixing the above items, you'll still leave one extra buffer allocation in your sequence; the one that failed to read. Not that it matter much in this case, as the caller has no idea how many strings were allocated in the first place (see previous item).
Shoring up all of the above would require a basic rewrite of nearly everything you have posted. In the end, the code would look so different, it's almost not worth trying to salvage what is here. Instead, look at what you have done, look at this list, and see where things went wrong. There's plenty to choose from.
Sample
#include <stdio.h>
#include <stdlib.h>
#define STR_MAX_LEN 46
char ** readFile(const char *fname)
{
char **strs = NULL;
int len = 0;
FILE *fp = fopen(fname, "r");
if (fp != NULL)
{
do
{
// array expansion
void *tmp = realloc(strs, (len+1) * sizeof *strs);
if (tmp == NULL)
{
// failed. cleanup prior success
perror("Failed to expand pointer array");
for (int i=0; i<len; ++i)
free(strs[i]);
free(strs);
strs = NULL;
break;
}
// allocation was good; save off new pointer
strs = tmp;
strs[len] = malloc( STR_MAX_LEN );
if (strs[len] == NULL)
{
// failed. cleanup prior sucess
perror("Failed to allocate string buffer");
for (int i=0; i<len; ++i)
free(strs[i]);
free(strs);
strs = NULL;
break;
}
if (fscanf(fp, "%45s", strs[len]) == 1)
{
++len;
}
else
{
// read failed. we're leaving regardless. the last
// allocation is thrown out, but we terminate the list
// with a NULL to indicate end-of-list to the caller
free(strs[len]);
strs[len] = NULL;
break;
}
} while (1);
fclose(fp);
}
return strs;
}
int main(int argc, char *argv[])
{
if (argc < 2)
exit(EXIT_FAILURE);
char **strs = readFile(argv[1]);
if (strs)
{
// enumerate and free in the same loop
for (char **pp = strs; *pp; ++pp)
{
puts(*pp);
free(*pp);
}
// free the now-defunct pointer array
free(strs);
}
return EXIT_SUCCESS;
}
Output (run against /usr/share/dict/words)
A
a
aa
aal
aalii
aam
Aani
aardvark
aardwolf
Aaron
Aaronic
Aaronical
Aaronite
Aaronitic
Aaru
Ab
aba
Ababdeh
Ababua
abac
abaca
......
zymotechny
zymotic
zymotically
zymotize
zymotoxic
zymurgy
Zyrenian
Zyrian
Zyryan
zythem
Zythia
zythum
Zyzomys
Zyzzogeton
Improvements
The secondary malloc in this code is completely pointless. You're using a fixed length word maximum size, so you could easily retool you array to be a pointer to use this:
char (*strs)[STR_MAX_LEN]
and simply eliminate the per-string malloc code entirely. That does leave the problem of how to tell the caller how many strings were allocated. In the prior version we used a NULL pointer to indicate end-of-list. In this version we can simply use a zero-length string. Doing this makes the declaration of readFile rather odd looking, but for returning a pointer-to-array-of-size-N, its' correct. See below:
#include <stdio.h>
#include <stdlib.h>
#define STR_MAX_LEN 46
char (*readFile(const char *fname))[STR_MAX_LEN]
{
char (*strs)[STR_MAX_LEN] = NULL;
int len = 0;
FILE *fp = fopen(fname, "r");
if (fp != NULL)
{
do
{
// array expansion
void *tmp = realloc(strs, (len+1) * sizeof *strs);
if (tmp == NULL)
{
// failed. cleanup prior success
perror("Failed to expand pointer array");
free(strs);
strs = NULL;
break;
}
// allocation was good; save off new pointer
strs = tmp;
if (fscanf(fp, "%45s", strs[len]) == 1)
{
++len;
}
else
{
// read failed. make the final string zero-length
strs[len][0] = 0;
break;
}
} while (1);
fclose(fp);
}
return strs;
}
int main(int argc, char *argv[])
{
if (argc < 2)
exit(EXIT_FAILURE);
char (*strs)[STR_MAX_LEN] = readFile(argv[1]);
if (strs)
{
// enumerate and free in the same loop
for (char (*s)[STR_MAX_LEN] = strs; (*s)[0]; ++s)
puts(*s);
free(strs);
}
return EXIT_SUCCESS;
}
The output is the same as before.
Another Improvement: Geometric Growth
With a few simple changes we can significantly cut down on the realloc invokes (we're currently doing one per string added) by only doing them in a double-size growth pattern. If each time we reallocate, we double the size of the prior allocation, we will make more and more space available for reading larger numbers of strings before the next allocation:
#include <stdio.h>
#include <stdlib.h>
#define STR_MAX_LEN 46
char (*readFile(const char *fname))[STR_MAX_LEN]
{
char (*strs)[STR_MAX_LEN] = NULL;
int len = 0;
int capacity = 0;
FILE *fp = fopen(fname, "r");
if (fp != NULL)
{
do
{
if (len == capacity)
{
printf("Expanding capacity to %d\n", (2 * capacity + 1));
void *tmp = realloc(strs, (2 * capacity + 1) * sizeof *strs);
if (tmp == NULL)
{
// failed. cleanup prior success
perror("Failed to expand string array");
free(strs);
strs = NULL;
break;
}
// save the new string pointer and capacity
strs = tmp;
capacity = 2 * capacity + 1;
}
if (fscanf(fp, "%45s", strs[len]) == 1)
{
++len;
}
else
{
// read failed. make the final string zero-length
strs[len][0] = 0;
break;
}
} while (1);
// shrink if needed. remember to retain the final empty string
if (strs && (len+1) < capacity)
{
printf("Shrinking capacity to %d\n", len);
void *tmp = realloc(strs, (len+1) * sizeof *strs);
if (tmp)
strs = tmp;
}
fclose(fp);
}
return strs;
}
int main(int argc, char *argv[])
{
if (argc < 2)
exit(EXIT_FAILURE);
char (*strs)[STR_MAX_LEN] = readFile(argv[1]);
if (strs)
{
// enumerate and free in the same loop
for (char (*s)[STR_MAX_LEN] = strs; (*s)[0]; ++s)
puts(*s);
// free the now-defunct pointer array
free(strs);
}
return EXIT_SUCCESS;
}
Output
The output is the same as before, but I added instrumentation to show when expansion happens to illustrate the expansions and final shrinking. I'll leave out the rest of the output (which is over 200k lines of words)
Expanding capacity to 1
Expanding capacity to 3
Expanding capacity to 7
Expanding capacity to 15
Expanding capacity to 31
Expanding capacity to 63
Expanding capacity to 127
Expanding capacity to 255
Expanding capacity to 511
Expanding capacity to 1023
Expanding capacity to 2047
Expanding capacity to 4095
Expanding capacity to 8191
Expanding capacity to 16383
Expanding capacity to 32767
Expanding capacity to 65535
Expanding capacity to 131071
Expanding capacity to 262143
Shrinking capacity to 235886
I know this same question has been asked a hundred times before, but they either don't help me or they aren't answered.
I want to read a text file which has some integers in a format like this:
1;50
2;40
3;180
this file can go forever so I can't create an array with a fixed size. So far the summarized part of what I have done (full code isn't like this, I have checked if files aren't null, made file pointers, put them in different functions etc.) :
int **mymatrix;
mymatrix =(int **) malloc(sizeof(int*)*1);
fscanf(file, "%d", &mymatrix[0]);
fscanf(file, ";%d", &mymatrix[1]);
and to print that:
printf("%d", *mymatrix[0]);
printf(" %d", *mymatrix[0]);
I have looked some similar questions and learned the malloc line from them.
I have tried doing fscanf(file, "%d;%d", something) and replaced something with every possible combination of *, **, &, && and also tried [0], [1] but still can't read anything.
I don't need that print part on my code (also tried every possible combinations but no luck). I had placed breakpoints after scanf's but Visual Studio shows mymatrix as < unable to read memory >.
So, there should be a combination of scanf that I haven't tried. If anyone can help me on that part, I greatly appreciate it.
Like this:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE *fp = fopen("matrix.txt", "r");
if(!fp){
perror("fopen");
return 1;
}
int d1, d2, rows = 0;
while(2 == fscanf(fp, "%d;%d", &d1, &d2))
++rows;
int **matrix = malloc(rows * sizeof(*matrix));
rewind(fp);
rows = 0;
while(2 == fscanf(fp, "%d;%d", &d1, &d2)){
matrix[rows] = malloc(2 * sizeof(**matrix));
matrix[rows][0] = d1;
matrix[rows++][1] = d2;
}
fclose(fp);
//print and free'd
for(int r = 0; r < rows; ++r){
printf("%d %d\n", matrix[r][0], matrix[r][1]);
free(matrix[r]);
}
free(matrix);
return 0;
}
realloc version.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE *fp;
int **matrix = NULL;
int d1, d2, r, rows = 0;
fp = fopen("data.txt", "r");
if(!fp){
perror("fopen");
return 1;
}
while(2 == fscanf(fp, "%d;%d", &d1, &d2)){
matrix = realloc(matrix, (rows+1)*sizeof(*matrix));//In the case of large files increase the size that you want to extend. It must have control of the timing.
matrix[rows] = malloc(2 * sizeof(**matrix));
matrix[rows][0] = d1;
matrix[rows][1] = d2;
++rows;
}
fclose(fp);
//print and free'd
for(r = 0; r < rows; ++r){
printf("%d %d\n", matrix[r][0], matrix[r][1]);
free(matrix[r]);
}
free(matrix);
return 0;
}
First, int **mymatrix; is not a matrix/2D array and cannot represent one.
Said that, you should use a pointer to a 1D array/matrix:
// avoid magic numbers!
#define COLS 2
// Points to the matrix. Starts without matrix
int (*mymatrix)[COLS] = NULL;
Despite its type, it can point to a 2D array. As a general rule, a "pointer to an array of N dimensions" can be used to address an "array of N+1 dimensions.
// the amount to grow the array (min. 1, but that is inefficient)
#define GROW_LENGTH 10
// this holds the total number of rows in the array
size_t length = 0;
// row to store next entry
size_t row = 0;
// buffer for input data
int buffer[COLS];
// read data until failure
while ( scanf("%d;%d", &buffer[0], &buffer[1]) == 2 ) {
if ( row >= length ) {
// enlarge the array for another block
int (*p)[COLS] = realloc(mymatrix,
sizeof(*mymatrix) * (length + GROW_LENGTH));
if ( p == NULL ) {
// realloc failed
// release the matrix and terminate (can be changed to more inteligent behaviour)
free(mymatrix);
exit(1);
}
// update variables
mymatrix = p;
length += GROW_LENGTH;
}
// store the data into the matrix
mymatrix[row][0] = buffer[0];
mymatrix[row][1] = buffer[1];
// next position in buffer
row++;
}
if ( mymatrix == NULL ) {
// nothing has been read
}
// process the data.
// `row` contains the number of rows with data
Don't forget to release the array when done:
free(mymatrix);
The code above is a fragment. It requires some standard headers and a function, of course. Best is to wrap the reading part into its own function with a clean interface to the caller. It also reads from stdin; change to fscanf is simple.
Also the printing part is straight-forward, just loop over all rows. and print each column.
Note that this code will allocate at most GROW_LENGTH - 1 unused rows. Set to 1 to have no overhead at all, but that is less efficient, as realloc is called fore every row. The best balance depends on the application, OS, etc.
First, your arguments to fscanf don't match the format string. mymatrix[0] is an int *, so &mymatrix[0] is an int **. Compiling with -Wall -Wextra will warn you of this.
Also, you allocate space for a 1 element array of int *, but then you don't populate that pointer.
You need to allocate an array of 2 int to assign to the first element of mymatrix, then pass the address of each of those to fscanf:
int **mymatrix;
mymatrix = malloc(sizeof(int*)*1); // don't cast the return value of malloc
mymatrix[0] = malloc(sizeof(int)*2); // same here
fscanf(file, "%d", &mymatrix[0][0]);
fscanf(file, ";%d", &mymatrix[0][1]);
Then you print them like this:
printf("%d", mymatrix[0][0]);
printf(" %d", mymatrix[0][1]);
When reading each subsequent line, you'll need to realloc instead of malloc and keep track of how many lines you have and which line you're on.
In addition to all of the other fine answers, why not use a pointer to array of int 2 (or whatever the size of your elements are)? In your circumstance, this is an optimal approach. There is no need to use a pointer to pointer to int. That complicates allocation and freeing of the memory. A pointer to array gives you single allocation of blocks, single freeing of all allocated memory and the 2D indexing you desire.
If you are reading from your file and storing a collection of integer pairs, you need only use a pointer to array, e.g.
int (*arr)[2] = NULL;
That makes allocation with either malloc or calloc a single call to allocate storage an initial number of pairs, and makes freeing the memory a single call. For example, if you have a variable maxn of 64, then to allocate a block of memory to hold the first 64 pairs of integers read from the file, you need only:
arr = calloc (maxn, sizeof *arr);
There is no need for a separate call to allocate storage for every 2-integers, when your reach your initial limit of 64, you simply realloc your array and keep going. The following uses a constant MAXN to realloc for an additional 64 pairs each time the current index idx reaches the limit maxn (the new block of memory is also zeroed):
if (++idx == maxn) {
printf ("\n reallocating %zu to %zu\n", maxn, maxn + MAXN);
size_t szelem = sizeof *arr;
void *tmp = realloc (arr, (maxn + MAXN) * szelem);
if (!tmp) {
fprintf (stderr, "realloc() error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
arr = tmp;
memset (arr + maxn * szelem, 0, MAXN * szelem);
maxn += MAXN;
}
Putting all the pieces together and using a few simply error checking functions for convenience, you could do something similar to the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* constants for number of columns, buffer chars, and initial allocation */
enum { NCOL = 2, MAXC = 32, MAXN = 64 };
void *xcalloc (size_t nmemb, size_t sz);
void *xrealloc (void *ptr, size_t psz, size_t *nelem);
FILE *xfopen (const char *fn, const char *mode);
int main (int argc, char **argv) {
char buf[MAXC] = {0};
char *fmt = "%d;%d";
int (*arr)[NCOL] = NULL;
size_t i, idx = 0, maxn = MAXN;
FILE *fp = argc > 1 ? xfopen (argv[1], "r") : stdin;
/* alloc mem for array of MAXN elements */
arr = xcalloc (maxn, sizeof *arr);
while (fgets (buf, MAXC, fp)) { /* read each line of input */
int a, b; /* parse line for values */
if (sscanf (buf, fmt, &a, &b) != NCOL) continue;
arr[idx][0] = a, arr[idx][1] = b;
if (++idx == maxn) /* realloc as needed */
arr = xrealloc (arr, sizeof *arr, &maxn);
}
if (fp != stdin) fclose (fp); /* close if not stdin */
for (i = 0; i < idx; i++)
printf (" array[%3zu][0] : %4d [1] : %d\n",
i, arr[i][0], arr[i][1]);
free (arr); /* free allocated memory */
return 0;
}
/** xcalloc allocates memory using calloc and validates the return. */
void *xcalloc (size_t nmemb, size_t sz)
{ register void *memptr = calloc (nmemb, sz);
if (!memptr) {
fprintf (stderr, "xcalloc() error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
return memptr;
}
/** realloc 'ptr' to array of elements of 'psz' to 'nelem + MAXN' elements */
void *xrealloc (void *ptr, size_t psz, size_t *nelem)
{ void *tmp = realloc ((char *)ptr, (*nelem + MAXN) * psz);
if (!tmp) {
fprintf (stderr, "realloc() error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
memset (tmp + *nelem * psz, 0, MAXN * psz); /* zero new memory */
*nelem += MAXN;
return tmp;
}
/** fopen with error checking - short version */
FILE *xfopen (const char *fn, const char *mode)
{ FILE *fp = fopen (fn, mode);
if (!fp) {
fprintf (stderr, "xfopen() error: file open failed '%s'.\n", fn);
// return NULL; /* choose appropriate action */
exit (EXIT_FAILURE);
}
return fp;
}
Example Input
With an initial allocation for 64 pairs, reallocation is forces in order to read the entire file. (you can set the initial size at 1 and realloc on every iteration, but that is highly inefficient -- the initial size for MAXN must be at least 1, and should be set to some reasonably anticipated number of elements given your data)
$ cat dat/2d_data.txt
1;354
2;160
3;205
4;342
...
98;464
99;130
100;424
Example Use/Output
$ ./bin/array_ptr2array_realloc <dat/2d_data.txt
array[ 0][0] : 1 [1] : 354
array[ 1][0] : 2 [1] : 160
array[ 2][0] : 3 [1] : 205
array[ 3][0] : 4 [1] : 342
...
array[ 97][0] : 98 [1] : 464
array[ 98][0] : 99 [1] : 130
array[ 99][0] : 100 [1] : 424
Memory Use/Error Check
In any code your write that dynamically allocates memory, you have 2 responsibilites regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you haven't written beyond/outside your allocated block of memory, attempted to read or base a jump on an unintitialized value and finally to confirm that you have freed all the memory you have allocated. For Linux valgrind is the normal choice.
$ valgrind ./bin/array_ptr2array_realloc <dat/2d_data.txt
==2796== Memcheck, a memory error detector
==2796== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==2796== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==2796== Command: ./bin/array_ptr2array_realloc
==2796==
array[ 0][0] : 1 [1] : 354
array[ 1][0] : 2 [1] : 160
array[ 2][0] : 3 [1] : 205
array[ 3][0] : 4 [1] : 342
...
array[ 97][0] : 98 [1] : 464
array[ 98][0] : 99 [1] : 130
array[ 99][0] : 100 [1] : 424
==2796==
==2796== HEAP SUMMARY:
==2796== in use at exit: 0 bytes in 0 blocks
==2796== total heap usage: 2 allocs, 2 frees, 1,536 bytes allocated
==2796==
==2796== All heap blocks were freed -- no leaks are possible
==2796==
==2796== For counts of detected and suppressed errors, rerun with: -v
==2796== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)
Always confirm All heap blocks were freed -- no leaks are possible and equally important ERROR SUMMARY: 0 errors from 0 contexts.
Look over all the answers and let me know if you have any further questions. Using a pointer to array makes a whole lot of sense in a number of situations such as this. It simplifies allocation and freeing of memory and preserves your 2D indexing as well.
If mymatrix were defined as int mymatrix[3][2], you could read the first line doing:
fscanf(file, "%d;%d", &mymatrix[0][0], &mymatrix[0][1]);
The same code would work with mymatrix defined as int **mymatrix, if it would point to a dynamically initialized array of pointers to arrays of int as follows:
mymatrix=(int**)calloc(lines, sizeof(int*)); // intialize the array of array
for (inti=0; i<lines; i++)
mymatrix[i]=(int*)calloc(cols, sizeof(int)); //intialise each array
The number of lines and cols of the matrix could then be defined at runtinme.
You will have to malloc the memory to mymatrix[0].
mymatrix[0]= (int *) malloc ( sizeof (int) *2);
Also, in mymatrix malloc, 1 actually means the maximum number of rows you will have. So you can at max have 1 row as per that.
I'm currently writing a method that reads from an allocated block of memory and prints out its contents from a certain offset and up to a specified size, both of which are passed as parameters. I'm using char pointers to accomplish this, but keep getting a malloc error around line
char *content = (char *)malloc(size+1);
Code for the method:
int file_read(char *name, int offset, int size)
{
//First find file and its inode, if existing
int nodeNum = search_cur_dir(name);
if(nodeNum < 0) {
printf("File read error: file does not exist\n");
return -1;
}
//Size check, to avoid overflows/overreads
if(offset > inode[nodeNum].size || size > inode[nodeNum].size || (offset+size) > inode[nodeNum].size) {
printf("File read error: offset and/or size is too large\n");
return -1;
}
int i, read_size, track_size = size, content_offset = 0;
int target_block = offset / BLOCK_SIZE; //Defined as constant 512
int target_index = offset % BLOCK_SIZE;
char *raw_content = (char *)malloc(inode[nodeNum].size+1);
printf("check1\n"); //Debug statment
for(i = target_block; i < (inode[nodeNum].blockCount-(size/BLOCK_SIZE)); i++) {
disk_read(inode[nodeNum].directBlock[i], raw_content+content_offset);
content_offset += BLOCK_SIZE;
}
printf("check2\n"); //Debug statment
char *content = (char *)malloc(size+1);
memcpy(content, raw_content+target_index, size);
printf("%s\n", content);
free(raw_content);
free(content);
return 0;
}
and code for disk_read:
char disk[MAX_BLOCK][BLOCK_SIZE]; //Defined as 4096 and 512, respectively
int disk_read(int block, char *buf)
{
if(block < 0 || block >= MAX_BLOCK) {
printf("disk_read error\n");
return -1;
}
memcpy(buf, disk[block], BLOCK_SIZE);
return 0;
}
structure for node
typedef struct {
TYPE type;
int owner;
int group;
struct timeval lastAccess;
struct timeval created;
int size;
int blockCount;
int directBlock[10];
int indirectBlock;
char padding[24];
} Inode; // 128 byte
The error I get when using this method is one of memory corruption
*** glibc detected *** ./fs_sim: malloc(): memory corruption (fast): 0x00000000009f1030 ***
Now the strange part is, firstly this only occurs after I have used the method a few times - for the first two or three attempts it will work and then the error occurs. For instance, here is an example test run:
% read new 0 5
z12qY
% read new 0 4
z12q
% read new 0 3
*** glibc detected *** ./fs_sim: malloc(): memory corruption (fast): 0x00000000009f1030 ***
Even stranger still, this error disappears completely when I comment out
free(raw_content);
free(content);
Even through this would tie up the memory. I've read through previous posts regarding malloc memory corruption and understand this usually results from overwriting memory bounds or under allocating space, but I can't see where I could be doing this. I've attempted other sizes for malloc as well and these produced the best results when I commented out the lines freeing both pointers. Does anyone see what I could be missing? And why does this occur so inconsistently?
Code allocates space for characters and a null character, but does not insure the array is terminated with a null character before printing as a string.
char *content = (char *)malloc(size+1);
memcpy(content, raw_content+target_index, size);
// add
content[size] = '\0';
printf("%s\n", content);
Likely other issues too.
[Edit]
OP code is prone to mis-coding and dependent on inode[] to have coherent values (.blockCount . size). Clarify and simplify by determining the loop count and allocating per that count.
int loop_count = (inode[nodeNum].blockCount-(size/BLOCK_SIZE)) - target_block;
char *raw_content = malloc(sizeof *raw_content * loop_count * BLOCK_SIZE);
assert(raw_count);
for (loop = 0; loop < loop_count; loop++) {
i = target_block + loop;
disk_read(inode[nodeNum].directBlock[i], raw_content + content_offset);
content_offset += BLOCK_SIZE;
}
Also recommend checking the success of disk_read()
While working on a program which requires frequent memory allocation I came across behaviour I cannot explain. I've implemented a work around but I am curious to why my previous implementation didn't work. Here's the situation:
Memory reallocation of a pointer works
This may not be best practice (and if so please let me knwow) but I recall that realloc can allocate new memory if the pointer passed in is NULL. Below is an example where I read file data into a temporary buffer, then allocate appropriate size for *data and memcopy content
I have a file structure like so
typedef struct _my_file {
int size;
char *data;
}
And the mem reallocation and copy code like so:
// cycle through decompressed file until end is reached
while ((read_size = gzread(fh, buf, sizeof(buf))) != 0 && read_size != -1) {
// allocate/reallocate memory to fit newly read buffer
if ((tmp_data = realloc(file->data, sizeof(char *)*(file->size+read_size))) == (char *)NULL) {
printf("Memory reallocation error for requested size %d.\n", file->size+read_size);
// if memory was previous allocated but realloc failed this time, free memory!
if (file->size > 0)
free(file->data);
return FH_REALLOC_ERROR;
}
// update pointer to potentially new address (man realloc)
file->data = tmp_data;
// copy data from temporary buffer
memcpy(file->data + file->size, buf, read_size);
// update total read file size
file->size += read_size;
}
Memory reallocation of pointer to pointer fails
However, here is where I'm confused. Using the same thought that reallocation of a NULL pointer will allocate new memory, I parse a string of arguments and for each argument I allocate a pointer to a pointer, then allocate a pointer that is pointed by that pointer to a pointer. Maybe code is easier to explain:
This is the structure:
typedef struct _arguments {
unsigned short int options; // options bitmap
char **regexes; // array of regexes
unsigned int nregexes; // number of regexes
char *logmatch; // log file match pattern
unsigned int limit; // log match limit
char *argv0; // executable name
} arguments;
And the memory allocation code:
int i = 0;
int len;
char **tmp;
while (strcmp(argv[i+regindex], "-logs") != 0) {
len = strlen(argv[i+regindex]);
if((tmp = realloc(args->regexes, sizeof(char **)*(i+1))) == (char **)NULL) {
printf("Cannot allocate memory for regex patterns array.\n");
return -1;
}
args->regexes = tmp;
tmp = NULL;
if((args->regexes[i] = (char *)malloc(sizeof(char *)*(len+1))) == (char *)NULL) {
printf("Cannot allocate memory for regex pattern.\n");
return -1;
}
strcpy(args->regexes[i], argv[i+regindex]);
i++;
}
When I compile and run this I get a run time error "realloc: invalid pointer "
I must be missing something obvious but after not accomplishing much trying to debug and searching for solutions online for 5 hours now, I just ran two loops, one counts the numbers of arguments and mallocs enough space for it, and the second loop allocates space for the arguments and strcpys it.
Any explanation to this behaviour is much appreciated! I really am curious to know why.
First fragment:
// cycle through decompressed file until end is reached
while (1) {
char **tmp_data;
read_size = gzread(fh, buf, sizeof buf);
if (read_size <= 0) break;
// allocate/reallocate memory to fit newly read buffer
tmp_data = realloc(file->data, (file->size+read_size) * sizeof *tmp_data );
if ( !tmp_data ) {
printf("Memory reallocation error for requested size %d.\n"
, file->size+read_size);
if (file->data) {
free(file->data)
file->data = NULL;
file->size = 0;
}
return FH_REALLOC_ERROR;
}
file->data = tmp_data;
// copy data from temporary buffer
memcpy(file->data + file->size, buf, read_size);
// update total read file size
file->size += read_size;
}
Second fragment:
unsigned i; // BTW this variable is already present as args->nregexes;
for(i =0; strcmp(argv[i+regindex], "-logs"); i++) {
char **tmp;
tmp = realloc(args->regexes, (i+1) * sizeof *tmp );
if (!tmp) {
printf("Cannot allocate memory for regex patterns array.\n");
return -1;
}
args->regexes = tmp;
args->regexes[i] = strdup( argv[i+regindex] );
if ( !args->regexes[i] ) {
printf("Cannot allocate memory for regex pattern.\n");
return -1;
}
...
return 0;
}
A few notes:
the syntax ptr = malloc ( CNT * sizeof *ptr); is more robust than the sizeof(type) variant.
strdup() does exactly the same as your malloc+strcpy()
the for(;;) loop is less error prone than a while() loop with a loose i++; at the end of the loop body. (it also makes clear that the loopcondition is never checked)
to me if ( !ptr ) {} is easyer to read than if (ptr != NULL) {}
the casts are not needed and sometimes unwanted.