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);
Related
So, my goal was to define a struct in which there is -
A command name (e.g. - "print")
Command arguments counter
A strings array containing the arguments.
You can review my code, but I'm really having a hard time understanding what am I doing wrong -
I use malloc to dynamically set my_struct.command size
I use malloc to dynamically set my_struct.arguments array size
I use realloc to dynamically increase my_struct.arguments size for every argument I set
I use malloc to dynamically set my_struct.arguments[i] size
I finally call cleanup(), to free any dynamically assigned pointers.
I keep getting LOTS of memory leaks. But I cannot understand why.
Help and tips will be kindly appreciated.
#include <stdio.h>
#include <stdlib.h>
struct {
char *command;
int arguments_count;
char **arguments;
} my_struct;
void cleanup(void);
int main() {
int i;
my_struct.command = (char *)malloc(6*sizeof(char));
my_struct.command = "print";
my_struct.arguments_count = 1;
my_struct.arguments = (char **)malloc(sizeof(char *));
my_struct.arguments[0] = "hello";
for(i = 1 ; i < 10; i++) {
my_struct.arguments = (char **)realloc(my_struct.arguments, sizeof(char *)*(i+1));
my_struct.arguments[i] = (char *)malloc(8*sizeof(char));
my_struct.arguments[i] = "hello";
my_struct.arguments_count++;
}
printf("Arguments count is: %d\n", my_struct.arguments_count);
printf("The arguments are:\n");
for(i = 0; i < 10; i++) {
printf("%s\n", my_struct.arguments[i]);
}
cleanup();
exit(0);
}
void cleanup(void) {
int i;
for(i = 0; i < 10; i++)
free(my_struct.arguments[i]);
free(my_struct.arguments);
free(my_struct.command);
}
strdup - The strdup() function returns a pointer to a new
string which is a duplicate of the string s. Memory for the new
string is obtained with malloc, and can be freed with free.
my_struct.command = strdup("print");
my_struct.arguments_count = 1;
my_struct.arguments = (char**) malloc(sizeof(char*));
my_struct.arguments[0] = strdup("hello");
for (int i=1; i < 10; ++i) {
// if the number of args is known, allocate before entering the loop
my_struct.arguments = (char**) realloc(my_struct.arguments, sizeof(char*)*(i+1));
my_struct.arguments[i] = strdup("hello");
my_struct.arguments_count++;
}
// in your cleanup use the arguments_count var instead of the literal 10
for (int i=0; i < my_struct.arguments_count; ++i)
Your mistake was:
// allocate a memory block of 6 bytes
// assign the address of that block to command
my_struct.command = malloc(6);
// then you assigned the address of the string 'print' to command
// therefore the previous allocated block is lost -> mem leak
my_struct.command = "print";
// strdup does the following
return memcpy(malloc(strlen(str) + 1), str, strlen(str) + 1);
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int isPresent(char *array[], char *string, int dimension) {
for (int i=0; i<dimension; i++) {
if (strcmp(array[i], string) != 0) {
continue;
} else {
return 1;
}
}
return 0;
}
int main(int argc, char *argv[]) {
int dim = 0;
char **without_duplicates = malloc(dim * sizeof(char *));
for (int i=1; i<argc; i++) {
if (!isPresent(without_duplicates, argv[i], dim)) {
realloc(without_duplicates, (dim + 1) * sizeof(char *));
without_duplicates[dim] = malloc((strlen(argv[i]) + 1) * sizeof(char));
strcpy(without_duplicates[dim], argv[i]);
printf("%s\n", without_duplicates[dim]);
dim++;
} else {
continue;
}
}
printf("%s\n", "Not duplicated arguments:");
for (int i=0; i<dim; i++) {
printf("%s\n", without_duplicates[i]);
}
return 0;
}
I execute the code: ./a.out rome turin rome milan venice milan florence.
But obtain segmentation fault error.
I tried to debug the code and it works until a certain point.
For example it copies rome, turin, discards rome, copies milan, but not venice and the other cities.
If it works for some cities why not with the others?
The program has an unexpected behavior, and crashes at different points with different arguments.
I don't know the number of arguments and their length, so the new array without the duplicates must be allocated dynamically.
In your code, you are not assigning the return value of realloc to any variable
realloc(without_duplicates, (dim + 1) * sizeof(char *));
According to cppreference:
On success, returns the pointer to the beginning of newly allocated memory. The returned pointer must be deallocated with free()or realloc(). The original pointer ptr is invalidated and any access to it is undefined behavior (even if reallocation was in-place).
On failure, returns a null pointer. The original pointer ptr remains valid and may need to be deallocated with free() or realloc().
Try doing something like
char** temp = realloc(without_duplicates, (dim + 1) * sizeof(char *));
if(temp != NULL) {
without_duplicates = temp
}
else {
//handle the unsuccessful allocation
}
Note: Similarly you need to check for malloc() whether the memory allocation was successful or not.
Try this: I also allowed myself to remove some useless statements within your code, hope you dont mind
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int isPresent(char *array[], char *string, int dimension)
{
for (int i=0; i<dimension; i++)
{
if (strcmp(array[i], string) == 0)
return 1;
}
return 0;
}
int main(int argc, char *argv[])
{
int dim = 0;
char ** without_duplicates = malloc(dim * sizeof(char *));
for (int i=1; i<argc; i++)
{
if (!isPresent(without_duplicates, argv[i], dim))
{
without_duplicates = realloc(without_duplicates, (dim + 1) * sizeof(char *));
without_duplicates[dim] = malloc((strlen(argv[i]) + 1) * sizeof(char));
strcpy(without_duplicates[dim], argv[i]);
dim++;
}
}
printf("%s\n", "Not duplicated arguments:");
for (int i=0; i<dim; i++)
{
printf("%s\n", without_duplicates[i]);
}
return 0;
}
Your problem was simply not getting the return value out of realloc function,
C is not what one may consider as a high-level programming language... If reallocating some memory, the variable storing that address must be aware of the new address of the new allocated memory hence you must store it:
without_duplicates = realloc(without_duplicates, (dim + 1) * sizeof(char *));
This caused segmentation fault because before storing the new allocated address you simply jumped to an address that does not exist within the context of your process and attempt store some data in it, that in result causes segmentation fault
in this code I want to get a number of friends and then get the names i want the strings will be allocated dynamically with the lengh of the user input i have used with 2 functions:
void getNum(char** names, int* num)
{
//somecode
names = (char*)malloc(*num * sizeof(char));
//check
}
void getNames(char** names, int* num)
{
int i = 0;
int len = 0;
char name[LEN] = { 0 };
getchar(); //buffer cleaning
for (i = 0; i < *num; i++)
{
printf("enter #%d friend name: ", i+1);
myFgets(name, LEN); //getting name and cleaning "\n" at end
len = strlen(name)+1; // getting the size of string include "/0"
*(names + i) = (char*)malloc(len * sizeof(char));
if (*(names[i]) == NULL)
{
printf("Error allocating memory!\n"); //print an error message
return 1; //return with failure
}
strncpy(*names, name, len);
}
}
the second dynamic allocation doens't work for me, overflow eror: "Access violation writing location". If the first allocation will be in the second function it will work fine. Can u explain that? and what I need to do for it will work in that way?
thank you in advance...
In function getNames, you used the wrong pointer to check for NULL, names[i] is *(names+i), not the same as *(names[i]), also, don't cast malloc's return value. No need to use sizeof(char), it's always 1.
*(names + i) = (char*)malloc(len * sizeof(char));
if (*(names[i]) == NULL) // compare to the wrong pointer
{
printf("Error allocating memory!\n"); //print an error message
return 1; //return with failure
}
strncpy(*names, name, len); // copy to the wrong buffer
Try the following:
names[i] = malloc(len);
if (names[i] == NULL)
{
printf("Error allocating memory!\n");
return 1; //return with failure
}
strncpy(names[i], name, len);
Also, in getNum, to allocate an array for char pointers, use
void getNum(char ***names, int *num) {
*names = malloc(*num * sizeof(char*));
}
You will call it by
char **names;
getNum(&names, &num);
You could also return it by doing char **getNum(...).
Assuming the first function should allocate an array of pointers, and that the second should allocate individual char arrays to store the individual names, you are lacking an indirection level in first function:
you pass it a copy of a char** (C pass parameters by copy)
you only use the local copy to store the result of the malloc (which is wrong BTW) and still keep original value in caller and eventually get a memory leak when leaving the function since nothing points to the allocated block any longer
It should be:
char** getNum(int num) /* no need to pass num by reference */
{
char **names;
//somecode
names = malloc(num * sizeof(char*)); /* do not cast resul of malloc in C */
//check
return names
}
And in second function, you should consistenly allocate memory for names[i] (or *(names + i)), test it for NULL and copy the string there:
names[i] = malloc(len * sizeof(char));
if (names[i] == NULL)
{
printf("Error allocating memory!\n"); //print an error message
return 1; //return with failure
}
strncpy(names[i], name, len);
Okay, imagine I have a char**, would this be the correct way to allocate memory?
I mean: allocate memory for the char** itself and then for each char*...
char** fraseUsuario = NULL;
int length = 100, i = 0;
fraseUsuario = (char **) malloc(sizeof (char*)); //Not pretty sure
for (i = 0; i < 3; i++) {
fraseUsuario[i] = (char *) malloc(length * sizeof (char));
if (fraseUsuario[i] == NULL) {
printf("error\n");
return -1;
}
gets(fraseUsuario[i]);
}
for (i = 0; i < 3; i++) {
printf("%s\n", fraseUsuario[i]);
free(fraseUsuario[i]);
}
And btw, how exactly does free() work? I mean, when I call it at the end, with the debugger it seems as if it does "nothing", if "Hello" is stored in the array, it will continue to be stored there after the free call... is that the normal behavior?
What do you mean allocate memory for the char ** itself? You allocate memory for a variable on the stack when you define it. The following statement defines (allocates memory) fraserUsuario and initializes it to NULL.
char **fraseUsuario = NULL;
I think what you probably meant is how to dynamically allocate an array of char **, i.e., pointer to a pointer to a character. Then you again dynamically allocate an array for each element of the previous allocated array. Do not use gets. It's deprecated and unsafe to use. Use fgets instead. Also, please don't cast the result of malloc. You don't get any benefit and you can run into error if you forget to include the header stdlib.h which contains its prototype. Here's how you do it.
char **fraseUsuario = NULL;
int max_string_len = 100 + 1; // maximum string length. +1 for null byte
int num_string = 3; // number of strings to read
int i, j;
fraseUsuario = malloc(num_string * sizeof *fraseUsuario);
if(fraseUsuario == NULL) { // check for NULL
// handle the case
printf("not enough memory\n");
return -1;
}
for(i = 0; i < num_string; i++) {
fraseUsuario[i] = malloc(max_string_len * sizeof(char));
if(fraseUsuario[i] == NULL) { // check for NULL
printf("not enough memory\n");
for(j = 0; j < i; j++)
free(fraseUsuario[j]); // free memory before returning
free(fraseUsuario); // free memory before returning
return -1;
}
if(fgets(fraserUsuario[i], max_string_len, stdin) == NULL) {
// reading string failed
*fraserUsuario[i] = '\0'; // empty string
}
}
for(i = 0; i < 3; i++) {
printf("%s\n", fraseUsuario[i]);
free(fraseUsuario[i]); // free memory allocated for strings
}
free(fraseUsuario); // free memory allocated for pointers to strings
fraseUsuario = NULL;
When you call free on a memory address which you got by a call to malloc, the memory block is returned to the free pool on the heap. This memory block can then later be reused by malloc. Once you free memory, you have given up your ownership of it. It no longer belongs to you and attempting to use it is illegal and will result in undefined behaviour and likely segfault.
You only allocate memory for one char* but use three.
To fix this do:
#define STR_MAXIMUM (3)
...
size_t length = 100, i = 0; /* No need to use a signed type.
size_t is meant as index and size type. */
char ** fraseUsuario = malloc(STR_MAXIMUM * sizeof(*fraseUsuario));
for (i = 0; i < STR_MAXIMUM; ++i)
{
fraseUsuario[i] = malloc(length * sizeof(*fraseUsuario));
...
Also add error checking to system calls.
Also^2: Do not use gets() as there is no way for the compiler or the machine to prevent the buffer passed in from overflowing. Use fgets() instead.
fgets(fraseUsuario[i], length, stdin);
I'm used to PHP, but I'm starting to learn C. I'm trying to create a program that reads a file line by line and stores each line to an array.
So far I have a program that reads the file line by line, and even prints each line as it goes, but now I just need to add each line to an array.
My buddy last night was telling me a bit about it. He said I'd have to use a multidimensional array in C, so basically array[x][y]. The [y] part itself is easy, because I know the maximum amount of bytes that each line will be. However, I don't know how many lines the file will be.
I figure I can make it loop through the file and just increment an integer each time and use that, but I feel that there might be a more simple way of doing it.
Any ideas or even a hint in the right direction? I appreciate any help.
To dynamically allocate a 2D array:
char **p;
int i, dim1, dim2;
/* Allocate the first dimension, which is actually a pointer to pointer to char */
p = malloc (sizeof (char *) * dim1);
/* Then allocate each of the pointers allocated in previous step arrays of pointer to chars
* within each of these arrays are chars
*/
for (i = 0; i < dim1; i++)
{
*(p + i) = malloc (sizeof (char) * dim2);
/* or p[i] = malloc (sizeof (char) * dim2); */
}
/* Do work */
/* Deallocate the allocated array. Start deallocation from the lowest level.
* that is in the reverse order of which we did the allocation
*/
for (i = 0; i < dim1; i++)
{
free (p[i]);
}
free (p);
Modify the above method. When you need another line to be added do *(p + i) = malloc (sizeof (char) * dim2); and update i. In this case you need to predict the max numbers of lines in the file which is indicated by the dim1 variable, for which we allocate the p array first time. This will only allocate the (sizeof (int *) * dim1) bytes, thus much better option than char p[dim1][dim2] (in c99).
There is another way i think. Allocate arrays in blocks and chain them when there is an overflow.
struct _lines {
char **line;
int n;
struct _lines *next;
} *file;
file = malloc (sizeof (struct _lines));
file->line = malloc (sizeof (char *) * LINE_MAX);
file->n = 0;
head = file;
After this the first block is ready to use. When you need to insert a line just do:
/* get line into buffer */
file.line[n] = malloc (sizeof (char) * (strlen (buffer) + 1));
n++;
When n is LINE_MAX allocate another block and link it to this one.
struct _lines *temp;
temp = malloc (sizeof (struct _lines));
temp->line = malloc (sizeof (char *) * LINE_MAX);
temp->n = 0;
file->next = temp;
file = file->next;
Something like this.
When one block's n becomes 0, deallocate it, and update the current block pointer file to the previous one. You can either traverse from beginning single linked list and traverse from the start or use double links.
There's no standard resizable array type in C. You have to implement it yourself, or use a third-party library. Here's a simple bare-bones example:
typedef struct int_array
{
int *array;
size_t length;
size_t capacity;
} int_array;
void int_array_init(int_array *array)
{
array->array = NULL;
array->length = 0;
array->capacity = 0;
}
void int_array_free(int_array *array)
{
free(array->array);
array->array = NULL;
array->length = 0;
array->capacity = 0;
}
void int_array_push_back(int_array *array, int value)
{
if(array->length == array->capacity)
{
// Not enough space, reallocate. Also, watch out for overflow.
int new_capacity = array->capacity * 2;
if(new_capacity > array->capacity && new_capacity < SIZE_T_MAX / sizeof(int))
{
int *new_array = realloc(array->array, new_capacity * sizeof(int));
if(new_array != NULL)
{
array->array = new_array;
array->capacity = new_capacity;
}
else
; // Handle out-of-memory
}
else
; // Handle overflow error
}
// Now that we have space, add the value to the array
array->array[array->length] = value;
array->length++;
}
Use it like this:
int_array a;
int_array_init(&a);
int i;
for(i = 0; i < 10; i++)
int_array_push_back(&a, i);
for(i = 0; i < a.length; i++)
printf("a[%d] = %d\n", i, a.array[i]);
int_array_free(&a);
Of course, this is only for an array of ints. Since C doesn't have templates, you'd have to either put all of this code in a macro for each different type of array (or use a different preprocessor such as GNU m4). Or, you could use a generic array container that either used void* pointers (requiring all array elements to be malloc'ed) or opaque memory blobs, which would require a cast with every element access and a memcpy for every element get/set.
In any case, it's not pretty. Two-dimensional arrays are even uglier.
Instead of an array here, you could also use a linked list, The code is simpler, but the allocation is more frequent and may suffer from fragmentation.
As long as you don't plan to do much random access (Which is O(n) here), iteration is about as simple as a regular array.
typedef struct Line Line;
struct Line{
char text[LINE_MAX];
Line *next;
};
Line *mkline()
{
Line *l = malloc(sizeof(Line));
if(!l)
error();
return l;
}
main()
{
Line *lines = mkline();
Line *lp = lines;
while(fgets(lp->text, sizeof lp->text, stdin)!=NULL){
lp->next = mkline();
lp = lp->next;
}
lp->next = NULL;
}
If you are using C you will need to implement the resizing of the array yourself. C++ and the SDL has this done for you. It is called a vector. http://www.cplusplus.com/reference/stl/vector/
While a multidimensional array can solve this problem, a rectangular 2D array would not really be the natural C solution.
Here is a program that initially reads the file into a linked list, and then allocates a vector of pointers of the right size. Each individual character does then appear as array[line][col] but in fact each row is only as long as it needs to be. It's C99 except for <err.h>.
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct strnode {
char *s;
struct strnode *next;
} strnode;
strnode *list_head;
strnode *list_last;
strnode *read1line(void) {
char space[1024];
if(fgets(space, sizeof space, stdin) == NULL)
return NULL;
strnode *node = malloc(sizeof(strnode));
if(node && (node->s = malloc(strlen(space) + 1))) {
strcpy(node->s, space);
node->next = NULL;
if (list_head == NULL)
list_head = node;
else
list_last->next = node;
list_last = node;
return node;
}
err(1, NULL);
}
int main(int ac, char **av) {
int n;
strnode *s;
for(n = 0; (s = read1line()) != NULL; ++n)
continue;
if(n > 0) {
int i;
strnode *b;
char **a = malloc(n * sizeof(char *));
printf("There were %d lines\n", n);
for(b = list_head, i = 0; b; b = b->next, ++i)
a[i] = b->s;
printf("Near the middle is: %s", a[n / 2]);
}
return 0;
}
You can use the malloc and realloc functions to dynamically allocate and resize an array of pointers to char, and each element of the array will point to a string read from the file (where that string's storage is also allocated dynamically). For simplicity's sake we'll assume that the maximum length of each line is less than M characters (counting the newline), so we don't have to do any dynamic resizing of individual lines.
You'll need to keep track of the array size manually each time you extend it. A common technique is to double the array size each time you extend, rather than extending by a fixed size; this minimizes the number of calls to realloc, which is potentially expensive. Of course that means you'll have to keep track of two quantities; the total size of the array and the number of elements currently read.
Example:
#define INITIAL_SIZE ... // some size large enough to cover most cases
char **loadFile(FILE *stream, size_t *linesRead)
{
size_t arraySize = 0;
char **lines = NULL;
char *nextLine = NULL;
*linesRead = 0;
lines = malloc(INITIAL_SIZE * sizeof *lines);
if (!lines)
{
fprintf(stderr, "Could not allocate array\n");
return NULL;
}
arraySize = INITIAL_SIZE;
/**
* Read the next input line from the stream. We're abstracting this
* out to keep the code simple.
*/
while ((nextLine = getNextLine(stream)))
{
if (arraySize <= *linesRead)
{
char **tmp = realloc(lines, arraysSize * 2 * sizeof *tmp);
if (tmp)
{
lines = tmp;
arraySize *= 2;
}
}
lines[(*linesRead)++] = nextLine;
)
return lines;
}