I have a text file from which I read words. After that, I have to write in a binary file each word and near it the row and column where it appears. At _strdup(p) my programm crashes. Does anyone know why? I would appreciate your help. Here is the code:
void create(const char *filename, const char ****matrix) {
FILE *u, *f;
u = fopen(filename, "wb");
assert(u != NULL);
f = fopen("in.txt", "r");
assert(f != NULL);
(*matrix) = (char ***)malloc(sizeof(char **) * 1);
int i = 0;
int j=0; char buff[1024];
while (fgets(buff, 1024, f)!=NULL) {
(*matrix) = realloc((*matrix), (i + 1) * sizeof(char **));
char *p = strtok(buff, " ().,");
(*matrix)[i] = (char **)malloc(sizeof(char *));
while (p) {
(*matrix)[i] = (char **)realloc((*matrix)[i], sizeof(char *)*(j + 1));
strcpy((*matrix)[i], buff);
(*matrix)[i][j] = _strdup(p);
fwrite((*matrix)[i][j], sizeof(char *), 1, u);
fwrite(&i, sizeof(int), 1, u);
fwrite(&i, sizeof(int), 1, u);
j++;
(*matrix)[i][j] = NULL;
p = strtok(NULL, " ().,");
}
(*matrix)[i] = NULL;
i++;
printf("\n");
}
fclose(u);
fclose(f);
}
The call to _strdup is likely failing because memory for (*matrix)[i][j] has not been allocated properly..
Using as many pointers as you are to read words from a file is not necessary, but given that you are using them, memory needs to be created for each, in the right order.
That is
matrix = malloc(sizeof(char *));
is the first of locations required before creating any others
For example, the method to create a properly allocated collection of pointers, for a 4 dimension array, might look like this:
char **** Create4D(int hR, int p, int c, int r)
{
char ****arr;
int w,x,y;
arr = calloc(hR, sizeof(char *));
for(w=0;w<hR;w++)
{
arr[w] = calloc(p, sizeof(char *));
for(x=0;x<p;x++)
{
arr[w][x] = calloc(c, sizeof(char *));
for(y=0;y<c;y++)
{
arr[w][x][y] = calloc(r, 1);
// ^ sizeof(char) == 1
}
}
}
return arr;
}
Note the italicized is to remind you that this is not actually creating a matrix, just a collection of memory addresses, some with space for pointers, others with space for strings of char.
To call this function:
char ****matrix = Create4D(2, 4, 6, 8);
if(matrix)//always test for success. If failed, matrix is set to NULL.
{
//use matrix
//With these arguments, 48 (2*4*6) pointers are created,
//each with space allocated to contain strings of 8 char each
....
Note also that in all of these calls, casting the return of [m][c]alloc is not used here, because it is not recommended in C. Also, if you plan create all of this memory, corresponding calls to free() must be made for each call to calloc().
Memory from calling the method above on my system is illustrated here:
Related
I have a 2d pointer array:
char **fields = calloc(1, sizeof(char *));
I add to it different strings, like this:
if(i > 0) fields = realloc(fields, (i+1) * sizeof(char *));
fields[i] = calloc(size, sizeof(char));
I then use memcpy into the fields[i] the desired string.
At the end of the program, when I try to free fields, I do it like this:
int j=0
while(fields != NULL && fields[j]){
free(fields[j]);
j++;
}
free(fields);
The program inserts 4 strings into fields.
The first string frees as expected, however on the second iteration of the loop (j=1) the program stops and outputs the error: free(): invalid pointer
EDIT: I made a short program with the same problem:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]){
char **fields = calloc(1, sizeof(char *));
int fieldsIndex = 0,i=0;
while (i<4) {
if(fieldsIndex > 0){
fields = realloc(fields, (fieldsIndex + 1) * sizeof(char *));
fields[fieldsIndex] =NULL;
printf("amount of field places: %d\n", (fieldsIndex + 1));
}
fields[fieldsIndex] = calloc(8, sizeof(char));
fields[fieldsIndex] = "88888888";
fieldsIndex++;
i++;
}
int j=0;
for(j=0; j<i; j++){
printf("field: %s\n", fields[j]);
free(fields[j]);
}
free(fields);
return 0;
}
Can anyone help?
Addressing mainly the MRE.
The main problems are around this line:
fields[fieldsIndex] = "88888888";
It's not right for two reasons:
Firstly you need one more element in the array for the null byte.
Secondly, you make the fields[fieldsIndex] pointers point to string literals, it not only causes a memory leak, but also those string literals are usually stored in a readonly section of memory, either way the behavior freeing a pointer pointing to a string literal is undefined.
You need to copy the strings to the memory you just allocated. Using memcpy should work as long as you reserve enough memory as mentioned in the previous point, a cleaner way would be to use strdup.
Another issue is if(fieldsIndex > 0) because then fields[0] will not have allocated memory.
Some other notes, if you know the amount of strings (i < 4) you shouldn't need to realloc, just allocate space for all the pointers in the first calloc* (assuming that is not brought about by the construction of the MRE) , also i and fieldsIndex seem to be redundant.
Here is a demo keeping realloc (as it's tangential to the OP):
int main()
{
char **fields = NULL;
char **tempfields; // I advise the use of an auxiliary pointer for reallocation
int fieldsIndex = 0;
while (fieldsIndex < 4)
{
tempfields = realloc(fields, (fieldsIndex + 1) * sizeof *fields); //*
if (!tempfields)
{
// handle the allocation error appropriately
}
fields = tempfields;
printf("amount of field places: %d\n", (fieldsIndex + 1));
fields[fieldsIndex] = strdup("88888888");
// Or
// fields[fieldsIndex] = calloc(9, sizeof **fields); // check return
// strcpy(fields[fieldsIndex], "88888888");
fieldsIndex++;
}
// With int iterator
int j = 0;
for (j = 0; j < fieldsIndex; j++)
{
printf("field: %s\n", fields[j]);
free(fields[j]);
}
free(fields);
}
Or with a sentinel element in fields:
Live demo
// With sentinel
tempfields = realloc(fields, (fieldsIndex + 1) * sizeof *fields);
if (!tempfields)
{
// handle the allocation error appropriately
}
fields = tempfields;
fields[fieldsIndex] = NULL;
while (*fields)
{
printf("field: %s\n", *fields);
free(*fields);
fields++;
}
free(tempfields);
I want to initialize array of char arrays in a function:
void myFunction(char*** words)
{
int size = 3;
char** words_ = (char**) malloc(size * sizeof(char*));
for (int i=0; i< size; ++i)
{
// init each word words[i] with some value
}
*words = words_;
}
which I use in that way:
char** multiple_words;
myFunction(&multiple_words);
Is there any other way to write this code better/simpler?
(This code works BTW).
char** myFunction()
{
int size = 3;
char** words_ = (char**) malloc(size * sizeof(char*));
for (int i=0; i< size; ++i)
{
// init each word words[i] with some value
}
return words_;
}
char **words = myFunction();
You can simplify the malloc call itself a bit. You don't need to cast the result of malloc in C1, so that call could be simplified to
char** words_ = malloc(size * sizeof *words); // sizeof *words == sizeof (char *)
Always check the result of a malloc, calloc, or realloc call. Even though the likelihood of the request failing is small, it's not zero.
The words_ variable really serves no purpose, and at first glance looked like you were redeclaring the words function argument. It would be simpler to get rid of it entirely and just write
*words = malloc( sizeof **words * size ); // sizeof **words == sizeof (char *)
leaving us with
void myFunction(char*** words)
{
int size = 3;
*words = malloc(size * sizeof **words);
if ( *words )
{
for (int i=0; i< size; ++i)
{
// init each word words[i] with some value
}
}
}
At least as of the 1989 standard - if you're using an ancient K&R-era implementation or if you're compiling this code as C++, then a cast is required. However, if you're writing C++, then you shouldn't be using malloc anyway.
I would create abstractions depending on what I want to represent:
struct word {
char *letters;
};
struct sentence {
struct word *words;
};
// and then work with those abstractions:
int sentence_create(struct sentence *s) {
const size_t size = 3;
s->words = malloc(size * sizeof(*s->words));
if (s->words == NULL) goto ERR_WORDS;
s->words[0] = strdup("hello");
if (s->words[0] == NULL) goto ERR_0;
s->words[1] = strdup("world");
if (s->words[1] == NULL) goto ERR_1;
s->words[2] = NULL;
// success
return 0;
// goto error handling
free(s->words[1]);
ERR_1:
free(s->words[0]);
ERR_0:
free(s->words);
s->words = NULL;
ERR_WORDS:
return -ENOMEM;
}
int main() {
struct sentence sentence;
if (sentence_create(&sentence) != 0) {
fprintf(stderr, "Oh no!");
abort();
}
// TODO: sentence_destroy(&sentence) to free memory
}
Also see wiki.c2 Three Star Programmer
Not sure 100% whether it is easier or not:
typedef struct {
char **words;
} WordList;
void myFunc(WordList *wordList) {
...
wordList->words = malloc(numberOfWords * sizeof(char *));
// strSource : this string comes from somewhere in your code
...
for (int i = 0; i < numberOfWords; i++) {
int numberOfChars = strlen(strSource);
(wordList->words)[i] = malloc((numberOfChars + 1) * sizeof(char));
(wordList->words)[i][numberOfChars] = '\0';
...
strcpy((wordList->words)[i], strSource)
...
}
...
}
int main() {
WordList wordList;
...
myFunc(&wordList);
...
}
This is gonna get icky no matter how you write it.
A char** is fine to use for pointing at the first item in an array of char*, each pointing at a string of individual length.
It is best if the function can return a char**, but if that isn't possible, then...
We'd have to return a char** through parameters, means we have to write char***. Three levels of indirection is always questionable, but this specific case is about the only valid use for it. Or the lesser evil at least, since...
Some makeshift struct wrapper that does nothing but hiding away the *** isn't making the code any better or more readable. That's very similar to hiding pointers behind typedef, not recommended.
The least messy way to write that might be something like this:
void heard (char*** word, size_t size)
{
char** the_word = malloc( sizeof(char*[size]) );
for(size_t i=0; i<size; i++)
{
const char* str = "bird"; // some random data from somewhere
the_word[i] = malloc (sizeof str); // allocate room for individual strings
strcpy(the_word[i], str);
}
*word = the_word;
}
Then call it as:
char** word;
heard(&word, 3);
for(size_t i=0; i<3; i++)
{
puts(word[i]);
}
The most proper solution is probably to use a complete string container class which handles all of this for you. Then you'd just declare arrays of strings and don't worry about all the details of allocating things manually.
So, here's my logic:
This is some text:
char *text;
Then this is array of texts:
char **arr;
Then array of these arrays is:
char ***arr2d;
And if I want a function to modify it, it needs to accept it as:
char ****arr2d;
And within the function use it as:
*arr2d = (e.g. allocate);
So if I want to create 2D array like this and make the first row, first column contain just a letter 'a', then why does this not work?
#define COLUMNS 7
void loadTable(char ****table)
{
*table = (char ***) malloc(sizeof(char**));
if (!*table) {
printf("Allocation error for table rows.");
return;
}
*table[0] = (char**) malloc(COLUMNS * sizeof(char*));
if (!*table[0]) {
printf("Allocation error for table columns.");
return;
}
*table[0][0] = (char*) malloc(2 * sizeof(char));
*table[0][0][0] = (char)(97);
*table[0][0][1] = '\0';
}
int main()
{
char ***table;
loadTable(&table);
return 0;
}
You would need only 3 *** to do what you describe, not 4 ****. Be aware, there are methods to allow you to avoid excessive depth in terms of arrays of arrays of strings. And there are also good reasons to avoid excessively deep orders of arrays, not the least is the need to free(.) everything you allocate. That means exactly one call to free(.) for each and every call to [m][c][re]alloc(.).
But to address your question...
In general, to create new memory for a single array of a previously allocated memory, you could use a function prototyped as:
char * ReSizeBuffer(char **str, size_t origSize);
Where if say the previously allocated buffer were created as:
char *buf = calloc(origSize, 1);
...the usage could look like:
char *tmp = {0};
tmp = ReSizeBuffer(&buf, newSize); //see implementation below
if(!tmp)
{
free(buf);
return NULL;
}
buf = tmp;
///use new buf
...
Then if this works for a single array of char, then the prototype for allocating new memory for a previously allocated array of strings might look like this:
char ** ReSizeBuffer(char ***str, size_t numArrays, size_t strLens);
Where if say the previously allocated 2D buffer were created as:
char **buf = Create2DStr(size_t numStrings, size_t maxStrLen); //see implementation below
...the usage could look like:
char **tmp = {0};
tmp = ReSizeBuffer(&buf, numStrings, maxStrLen);
if(!tmp)
{
free(buf);
return NULL;
}
buf = tmp;
///use new buf
...
Implementations:
Implementation of ReSizeBuffer. This must be expanded if you desire to implement the second prototype:
char * ReSizeBuffer(char **str, size_t size)
{
char *tmp={0};
if(!(*str)) return NULL;
if(size == 0)
{
free(*str);
return NULL;
}
tmp = (char *)realloc((char *)(*str), size);
if(!tmp)
{
free(*str);
return NULL;
}
*str = tmp;
return *str;
}
Implementation of Create2DStr might look like this:
char ** Create2DStr(size_t numStrings, size_t maxStrLen)
{
int i;
char **a = {0};
a = calloc(numStrings, sizeof(char *));
for(i=0;i<numStrings; i++)
{
a[i] = calloc(maxStrLen + 1, 1);
}
return a;
}
I just stumbled upon this old question of mine and spotted the problem immediately. Here is the answer:
The number of asterisks is actually correct, the problem is operator evaluation. Specifically, all lines of code of this form:
*table[0]
should have been written as:
(*table)[0]
I'm having some trouble reading in data from a file into an array of memory allocated structs in c. My relevant code is as follows:
//Struct that holds the restaurant information
typedef struct
{
char *name;
char *food;
double *price;
int *rating;
}RESTAURANT;
//Function to get all the reviews from the file
void reviews()
{
int numReviews, i;
char tempBuffer[BUFFER_SIZE]; //hold the user input
RESTAURANT *reviews; //create an array of structs
FILE *inputFile; //file pointer
inputFile = fopen(INPUT_FILE_NAME, "r"); //open the input file
//Get the number of reviews from the top of the file
fgets(tempBuffer, BUFFER_SIZE, inputFile);
sscanf(tempBuffer, "%d", &numReviews);
//Allocate enough space in the struct array for the number of reviews
reviews = malloc(sizeof(*reviews)*numReviews);
//Loop to allocate memory for each field in each struct
for(i = 0; i < numReviews; i++)
{
reviews[i].name = malloc(sizeof(char *));
reviews[i].food = malloc(sizeof(char *));
reviews[i].price = malloc(sizeof(double *));
reviews[i].rating = malloc(sizeof(int *));
}
//Loop to get each field for each struct from the file
//And store it in the struct array at the correct struct
for(i = 0; i < numReviews; i++)
{
fscanf(inputFile, "%s", reviews[i].name);
fscanf(inputFile, "%s", reviews[i].food);
fscanf(inputFile, "%lf", reviews[i].price);
fscanf(inputFile, "%d", reviews[i].rating);
}
And the file at reviews.txt is:
4
Chili's
AmericanizedMexican
10.95
3
BurgerKing
American
4.50
2
IHOP
American
9.50
1
OliveGarden
AmericanizedItalian
11.00
4
Reading in Chili's and AmericanizedMexican works fine. But when I try to print the price or rating of Chili's the price always prints 0.0 and the rating is always some huge number over 1 million. What am I doing wrong here? I'm guessing it must be either something with allocating the memory or something with the way I'm meant to read it in.
I don't know, but storing scalar values like price and rating as allocated data via pointers seems strange. You can do that, but it adds a lot of allocation overhead. Remeber that you have to free everything that you have allocated.
Besides that, you got the allocation wrong:
reviews[i].name = malloc(sizeof(char *));
reviews[i].food = malloc(sizeof(char *));
reviews[i].price = malloc(sizeof(double *));
reviews[i].rating = malloc(sizeof(int *));
You allocate memory to hold something the size of a pointer. You must allocate memory that can hold the thing pointed to. A useful allocation pattern is:
x = malloc(sizeof(*x));
for single values and
x = malloc(count * sizeof(*x));
for arrays of length count. You do that already for reviews. Your strings, i.e. char arrays, should be such arrays. So you should allocate:
reviews[i].name = malloc(MAX_LEN * sizeof(char));
reviews[i].food = malloc(MAX_LEN * sizeof(char));
reviews[i].price = malloc(sizeof(double));
reviews[i].rating = malloc(sizeof(int));
where MAX_LEN is a more or less arbitrary limit that you must set and enforce. (For example, you should make sure that fscanf never writes more than ´MAX_LEN` characters to the buffer; that includes the trailing null character.)
Your treatment of the scalar values is awkward. I'd change the struct to
typedef struct {
char *name;
char *food;
double price; // Store values, not pointers
int rating; // Same here
} RESTAURANT;
Throw out the allocation and scan directly into these fields, using the address operator & to get a pointer:
fscanf(inputFile, "%lf", &reviews[i].price);
fscanf(inputFile, "%d", &reviews[i].rating);
your problem is
for(i = 0; i < numReviews; i++)
{
reviews[i].name = malloc(sizeof(char *));
reviews[i].food = malloc(sizeof(char *));
reviews[i].price = malloc(sizeof(double *));
reviews[i].rating = malloc(sizeof(int *));
}
Here, sufficient memory is not allocated.
do this
for(i = 0; i < numReviews; i++)
{
reviews[i].name = malloc(128 *sizeof(char));
reviews[i].food = malloc(128 *sizeof(char));
reviews[i].price = malloc(sizeof(double));
reviews[i].rating = malloc(sizeof(int));
}
EDIT:
The value 128 is used for demonstration purpose only, just to point out the erroneous part in OP's code.
Say I assigned an array like so:
char* array[]={"This"};
And then later I wanted to assign array[ ] a new value so that it stores "This" and "That," is there a way that I could change the size of array so that it could hold a new number of values?
No, you can't change the size of an array. You could use a dynamically allocated list of char* instead and realloc() as required:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int main()
{
char** array = malloc(1 * sizeof(*array));
if (array)
{
array[0] = "This";
printf("%s\n------\n", array[0]);
char** tmp = realloc(array, 2 * sizeof(*array));
if (tmp)
{
array = tmp;
array[1] = "That";
printf("%s\n", array[0]);
printf("%s\n", array[1]);
}
free(array);
}
return 0;
}
See online demo: https://ideone.com/ng00k.
There is no way to resize an array. You can simply create a new array of size 2, then copy all the data from the previous one to the new one. realloc does it for you with dynamic memory. The better way is to use data structures such as LinkedLists or Vectors which you can find more about online.
You cannot resize array objects.
You would have to dynamically allocate the memory for array and extend it using realloc. Example:
size_t current_size = 0;
char **array = malloc((current_size + 1) * sizeof *array);
if (array)
{
array[current_size++] = "This";
}
...
/**
* If realloc cannot extend the buffer, it will return NULL and leave
* the original buffer intact; however, if we assign NULL back to array,
* we lose our handle to the original buffer, causing a memory leak, so
* we assign the result to a temporary variable.
*/
char **tmp = realloc(array, (current_size + 1) * sizeof *array)
if (tmp)
{
array = tmp;
array[current_size++] = "That";
}
else
{
// realloc failed to extend the buffer; original buffer
// is left intact.
}
Caveats:
realloc is a relatively expensive call, so you (generally) don't want to extend your buffer one element at a time like I did here. A more common strategy is to pick an initial starting size that covers most cases, and if you need to extend the buffer, double its size.
You could abstract the resize operation into a separate function, like so:
int addItem(char ***arr, char *newElement, size_t *count, size_t *bufSize)
{
if (*count == *bufSize)
{
// we've run out of room; extend the buffer
char **tmp = realloc(**arr, 2 * *bufSize * sizeof **arr);
if (tmp)
{
*arr = tmp;
*bufSize *= 2;
}
else
{
// could not extend the buffer; return failure code
return 0;
}
}
(*arr)[(*count)++] = newElement;
}
and call it as
#define N ... // initial array size
char **array = malloc(N * sizeof *array);
size_t bufSize = N;
size_t count = 0;
...
if (addItem(&array, "This", &count, &bufSize))
printf("# elements = %zu, buffer size = %zu\n", count, bufSize);
if (addItem(&array, "That", &count, &bufSize))
printf("# elements = %zu, buffer size = %zu\n", count, bufSize);
This is all untested and off the top of my head; no warranties express or implied. But it should be enough to point you in the right direction.
This is not possible. You can allocate an array of char*, though:
char **array = calloc(2, sizeof(char *));
array[0] = "This";
array[1] = "That";