Deallocation of memory in arrays - c

I've done a program that opens the file (read binary), and saves all the words(in the file) in an array of char (allocated dynamically in base of the length of the word).
This is the code:
char **leggi_stringhe(const char *filename, size_t *size) {
FILE *f = fopen(filename, "rb");
if (f == NULL) {
*size = 0;
return NULL;
}
int x;
if (fread(&x, 1, 4, f) != 4) {
*size = 0;
return NULL;
}
char **stringhe = malloc((x) * sizeof(char));
for (int i = 0; i < x; i++) {
int z = 0;
if (fread(&z, 1, 4, f) != 4) {
*size = 0;
return NULL;
}
stringhe[i] = malloc((z)* sizeof(char));
if (fread(stringhe[i], 1, z, f) != z) {
*size = 0;
return NULL;
}
stringhe[i][z] = 0;
}
*size = x;
fclose(f);
return stringhe;
}
int main(void) {
size_t t;
char **a = leggi_stringhe("file1.bin", &t);
for (int i = 0; i < t; i++)
free(a[i]);
free(a);;
}
The program works, but i have problems with memory deallocation.
After calling of leggi_stringhe function, the variable a contains:
a[0] = "first"
a[1] = "second"
a[2] = "third"
but when i'm trying to deallocate the whole a variable as i wrote, the debugger stops with a warning.
I was inspired by this question for writing my code Using Dynamic Memory allocation for arrays, but do not understand why I get this error when i try to deallocate.

Your initial call to malloc is wrong. You allocate space for x characters, not for pointers to char.
Your second call inside the loop is wrong to, as you don't allocate space for the terminator.
Lastly, and unrelated to the problems you ask about, but if the fread calls inside the loop fails, you will have memory leaks.

There are some problems with your code:
This line:
char **stringhe = malloc((x) * sizeof(char));
Needs to be:
char **stringhe = malloc((x) * sizeof(char*)); /* or sizeof *stringhe */
As you need to allocate x char* pointers for stringhe.
Inside your first for loop, you are not adding +1 for null-terminator. It needs to be instead:
stringhe[i] = malloc(z+1); /* sizeof(char) = 1 */
You need to check return of malloc(). It can return NULL if unsuccessful. You can do this by simply checking if (ptr == NULL), then exit the program. It would unsafe to allow a failed malloc() to continue in the program.
for (int i = 0; i < t; i++) is comparing an int with size_t. This should be for (size_t i = 0; i < t; i++) instead.

Related

How do I initialize a 2D char array with dynamic memory allocation in C?

I'm writing a function that copies the contents of a text file (arranged into a table) into a 2D array, just without the spaces. For example, if table.txt is
A B C
D E F
G H I
then the generated array would be equivalent to
char tableArray[ROWS][COLS] = {{'A', 'B', 'C'}, {'D', 'E', 'F'}, {'G', 'H', 'I'}};
I'm having trouble with the initialization of said array.
The function currently looks like this:
#define ROWS 3
#define COLS 3
char tableArray[ROWS][COLS];
//proper initialization of tableArray here. Not sure what to put
void copyTable(){
//copies the characters of the table into an array
FILE *fp = fopen("table.txt", "r");
if (fp == NULL) {
printf("No file found.");
return;
}
char c;
int currentRow;
int currentCol;
//Iterate through the file character by character
for (currentRow = 0; currentRow < ROWS; currentRow++) {
for (currentCol = 0; currentCol < COLS; currentCol++) {
c = fgetc(fp);
if (!(c == ' ')) {
tableArray[currentRow][currentCol] = c;
}
fgetc(fp); //skip newline character at end of row
}
}
tableArray[ROWS][COLS] = '\0';
}
But this code won't work due to a lack of memory allocation. I tried doing something like
char tableArray[ROWS][COLS];
int** tableArray;
tableArray = (int**)malloc(ROWS * sizeof(int*));
for (int i = 0; i < ROWS; i++) {
tableArray[i] = (int*)malloc(COLS * sizeof(int));
}
but I don't really understand what that code does, and it yields an error: 'tableArray' does not name a type, which I've failed to fix.
So how do I properly initialize tableArray? If there's another problem in the function irrespective of this part, please let me know.
When we know the data dimensions (e.g. 3x3), call a function to handle the allocation and reading.
Allocate to the referenced object, not to the type. Easier to code right, review and maintain.
Test for allocation success.
Read with fgetc() and test it.
Use size_t for sizing and indexing.
I'd recommend unsigned char for the data type as it is more clear on what is being saved the char, but use whatever type you want.
unsigned char** read_char_matrix(FILE *inf, size_t rows, size_t cols) {
unsigned char **table = malloc(sizeof table[0] * rows);
if (table == NULL) {
return NULL;
}
for (size_t c = 0; c < cols; c++) {
table[c] = malloc(sizeof table[c][0] * cols);
if (table[c] == NULL) {
while (c > 0) {
free(table[--c]);
}
free(table);
return NULL;
}
}
for (size_t r = 0; r < rows; r++) {
for (size_t c = 0; c < cols; c++) {
int ch = fgetc(inf);
if (!isalpha(ch)) {
TBD_Code_to_handle_error();
}
table[r][c] = (unsigned char) ch;
ch = fgetc(inf);
if (!isspace(ch)) {
TBD_Code_to_handle_error();
}
}
}
return table;
}

is there a way for Realloc in functions correctly? [duplicate]

This question already has answers here:
C Programming: malloc() inside another function
(9 answers)
Closed 2 years ago.
this function get an memory allocated input(with size : 1 bytes) from user and put it in heap data. it works correctly in function but when this function ends and come back to main, input will be corrupted. it happens when re-allocate function change the address of strings in heap memory. can anyone help me to fix it?
int main() {
char* input = (char*)malloc(sizeof(char));
example(input);
printf("%s", input);
}
void example(char* input) {
int i = 0;
char* a = "qweqeqweqweqweqweqwasdfsdfsdgasdgg";
for (int i = 0; i < 20; i++) {
input = (char*)realloc(input, sizeof(char) * i + 1);
input[i] = a[i];
}
}
The realloc function can return a pointer that was different from what was passed in. If that happens, the copy of input you have in the main function is invalid.
You can fix this by having example return the modified pointer and assigning to back to input in the main function. Also:
Don't cast the return value of realloc
If realloc fails the original pointer is still valid, so assign to a temporary and check the return value
You need to add a terminating null byte to the string and allocate additional space for it.
So your function would become this:
char *example(char* input) {
int i = 0;
char* a = "qweqeqweqweqweqweqwasdfsdfsdgasdgg";
for (int i = 0; i < 20; i++) {
char *tmp = realloc(input, i + 1 + 1);
if (!tmp) {
perror("relloc failed");
free(input);
exit(1);
}
input = tmp;
input[i] = a[i];
}
intput[i] = 0;
return input;
}
And you call it like this:
input = example(input);
You should also move the definition of example to before main, that way it can be called correctly.
The way you call realloc is wrong. You should use a temporary variable to save the pointer because if realloc fails you will loose the reference the original memory block.
char *example(char* input);
int main(void)
{
char *input = malloc(sizeof(*input));
char *tmp;
if((tmp == example(input))) input = tmp;
printf("%s", input);
}
char *example(char* input) {
int i = 0;
char* a = "qweqeqweqweqweqweqwasdfsdfsdgasdgg";
for (int i = 0; i < 20; i++)
{
char *tmp = realloc(input, sizeof(*input) * (i + 2));
if(tmp)
{
input = tmp;
input[i] = a[i];
input[i + 1] = 0;
}
else
{
/* handle allocation error */
}
}
return tmp;
}
You can also use pointer to pointer but you need to save the original pointer to avoid potential memory leak:
int main(void)
{
char *input = malloc(sizeof(*input));
char *tmp = input;
example(&tmp);
if(tmp) input = tmp;
printf("%s", input);
}
void example(char** input) {
int i = 0;
char* a = "qweqeqweqweqweqweqwasdfsdfsdgasdgg";
for (int i = 0; i < 20; i++)
{
*input = realloc(*input, sizeof(*input) * (i + 2));
if(*input)
{
*input = tmp;
(*input)[i] = a[i];
(*input)[i + 1] = 0;
}
else
{
/* handle allocation error */
}
}
}
Another problem in your code: you do not null terminate your string.
You need to read warnings. You have more issues in your code - for example, you call function without prototype.

Print last few lines of a text file

Currently, I am trying to create a C program that prints the last few lines of a text file, read in through the command line. However, it is currently causing a segmentation error when I try to copy the strings from fgets into the main array. I have been unable to fix this, and so have not been able to test the rest of my code. How would I begin to fix the segmentation error? I have posted the code below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int i=1,j,printNumber;
char **arr = (char **) malloc (100 * sizeof(char *));
char *line = (char *) malloc (80 * sizeof(char));
if (argc == 1) {
printNumber = 10;
}
else {
printNumber = atoi(argv[1]);
}
while (fgets(line,80,stdin) != NULL) {
if (line != NULL) {
line[strlen(line)-1] = '\0';
strcpy(arr[i],line); //SEGMENTATION ERROR!!!!
}
else {
free(line);
strcpy(arr[i],NULL);
}
i++;
printf("%d ",i);
}
free(arr);
for (j = i-printNumber-1; j < i-1; j++) {
printf("%s ", arr[j]);
}
printf("\n");
return 0;
}
You are allocating space for arr, which is a pointer to a pointer to char, but not allocating any individual char * pointers within arr.
Since you allocated arr with the size of 100 * sizeof(char *), I assume you want 100 sub-entries in arr. Sure:
for(i = 0; i < 100; i++)
arr[i] = malloc(80 * sizeof(char));
Then, when you free arr:
for(i = 0; i < 100; i++)
free(arr[i]);
free(arr);
Note that it is good practice to always check malloc for failure (return value of NULL) and handle it, and to set pointers to NULL after freeing them once to avoid double-free bugs.
You don't always know the length of the longest line (not until you try to read) OR how many last lines you are expected to keep track of (but is given at runtime). Thus, both of these values need to be known before you allocate memory or delegated to a function that does it for you.
#include <stdio.h>
#include <stdlib.h>
struct Line {
char *line; // content
size_t storage_sz; // allocation size of line memory
ssize_t sz; // size of line, not including terminating null byte ('\0')
};
int main(int argc, char *argv[]) {
int max_lines = 10;
if (argc > 1) {
max_lines = atoi(argv[1]);
}
if (max_lines < 0) {
fprintf(stderr, "%s\n", "Sorry, no defined behaviour of negative values (yet)\n");
return EXIT_FAILURE;
}
// keep an extra slot for the last failed read at EOF
struct Line *lines = (struct Line *) calloc(max_lines + 1, sizeof(struct Line));
int end = 0;
int size = 0;
// only keep track of the last couple of lines
while ((lines[end].sz = getline(&lines[end].line, &lines[end].storage_sz, stdin)) != -1) {
end++;
if (end > max_lines) {
end = 0;
}
if (size < max_lines) {
size++;
}
}
// time to print them back
int first = end - size;
if (first < 0) {
first += size + 1;
}
for (int count = size; count; count--) {
// lines might contain null bytes we can't use printf("%s", lines[first].line);
fwrite(lines[first].line, lines[first].sz, 1u, stdout);
first++;
if (first > size) {
first = 0;
}
}
// clear up memory after use
for (int idx = 0; idx <= max_lines; idx++) {
free(lines[idx].line);
}
free(lines);
return EXIT_SUCCESS;
}

C - strpy, char*** crashing

I'm writing code for an assignment where we have to create a hashtable. One of the functions is to get all the keys within the hash table and assign it into a char* ** (triple pointer) given by the parameters. The char* ** is presumed to be empty, and so we have to allocate memory to it within the function to fit all the keys.
The problem I'm having is where, after I allocate memory (and presumably the right amount, with strlen + 1), the program crashes and valgrind gives me an error message of invalid read of size 8, as well as a bunch of unconditional jumps and finally Process terminating with default action of signal 11 (SIGSEGV) Access not within mapped region at address 0x0.
int GetKeys( HashTablePTR hashTablePtr, char ***keysArrayHandle, unsigned int *keyCount )
{
HashTablePTR head;
int counter = 0;
size_t length = 0;
*keyCount = 0;
head = hashTablePtr;
if (NULL == hashTablePtr || 0xDEADBEEF != hashTablePtr[0].sentinel)
{
return(-1);
}
else
{
// Get key count
for (int i = 0; i < (int) head[0].range; i++)
{
hashTablePtr = &(head[i]);
while (NULL != hashTablePtr && NULL != hashTablePtr->key)
{
*keyCount = *keyCount + 1;
hashTablePtr = hashTablePtr->next;
}
}
printf("keyCount: [%d]\n", *keyCount);
}
keysArrayHandle = malloc(sizeof(char **) * (*keyCount));
for(int j = 0; j < (int) head[0].range; j++)
{
hashTablePtr = &(head[j]);
while (NULL != hashTablePtr && NULL != hashTablePtr->key && counter < *keyCount)
{
length = strlen(hashTablePtr->key) + 1;
keysArrayHandle[counter] = malloc(sizeof(char) * length);
printf("%s\n", hashTablePtr->key);
///////SOMETHING IS WRONG WITH THIS LINE UNDERNEATH////////
memcpy(*(keysArrayHandle[counter]), hashTablePtr->key, length);
printf("String copied\n");
counter++;
hashTablePtr = hashTablePtr->next;
}
}
return(0);
}
keysArrayHandle[counter] = malloc(sizeof(char) * length);
returns a pointer to keysArrayHandle[counter].
Then you are using *(keysArrayHandle[counter]) instead of keysArrayHandle[counter] in memcpy.
maybe you should
*(keysArrayHandle[counter]) = malloc(sizeof(char) * length);
valter
I think you should not dereference that pointer there
something = malloc(size);
memcpy(something, x, size); /* instead of memcpy(*something ... */
Also, check mpthe value returned by malloc

Frequency array dynamic allocation using C

I have a function that goes through my array of strings to find out how many times that string occurs with in an array. If found, the string will be set to NULL and a counter keeps track of how many times the string is found. I then call another function within the loop to allocate memory for my frequency array so that I can store count. It seems to work fine, but when I go and create any other variable within main my program crashes. Here are my two functions:
int search(char **table, int **frequency, int wordSize)
{
// Local Declaration
int i, j, k;
int count = 1;
int strCount = 0;
char target[25];
// Statement
for(i = 0, k = 0; i < wordSize; i++)
{
if(table[i] != NULL)
{
strcpy(target, table[i]);
for(j = i + 1; j < wordSize; j++)
{
if(table[j] != NULL &&
strcmp(target, table[j]) == 0 &&
target != table[i])
{
count++;
free(table[j]);
table[j] = NULL;
}
}
strCount += makeFreq(frequency, k, count);
k++;
}
count = 1;
}
return strCount;
}// search
int makeFreq(int **frequency, int k, int count)
{
// Local Declaration
int strCount = 0;
// Statement
frequency[k]=(int*)malloc(sizeof(int));
frequency[k][0] = count;
strCount += 1;
return strCount;
}// makeFreq
Can someone explain to my why my program is crashing?
Here I allocated 1000 pointers for my table.
char** getPoint(void)
{
// Local Declaration
char **table;
// Statement
table = (char**)calloc(MAX_SIZE + 1, sizeof(char));
if(table == NULL)
{
MEM_ERROR, exit(100);
}
return table;
}// getPoint
Than I read I allocate memory for the strings in my file and store it into the array of strings.
int scanFile(char **table, FILE *fpFile)
{
// Local Declaration
int count = 0;
char temp[500];
char **ptr = table;
// Statement
// scan file, allocate, and copy string to array.
while(fscanf(fpFile, "%s", temp) != EOF)
{
*(ptr + count) =(char*)calloc(strlen(temp)+1, sizeof(char));
strcpy(*(ptr + count), temp);
count++;
}
return count;
}// scanFile
Here is how I allocated the array of pointers for my frequency array.
void aloFreqAry(int **frequency, int wordSize)
{
// Local Declaration
// Statement
frequency =(int**)calloc(wordSize + 1, sizeof(int));
if(frequency == NULL)
{
MEM_ERROR, exit(103);
}
return;
}// aloFreqAry
Apart from the problem of the sizes in the allocations (should be sizeof(char*) in the allocation of table, and sizeof(int*) in the allocation of frequency),
void aloFreqAry(int **frequency, int wordSize)
{
// Local Declaration
// Statement
frequency =(int**)calloc(wordSize + 1, sizeof(int));
if(frequency == NULL)
{
MEM_ERROR, exit(103);
}
return;
}// aloFreqAry
doesn't allocate anything to the frequency in the caller. It just allocates memory to the local copy of that pointer, and loses the handle to that when the function returns.
Instead of taking an int** as argument, the function should return one,
frequency = calloc(wordSize + 1, sizeof(int*)); // size of a _pointer_ to int
if(frequency == NULL)
{
MEM_ERROR, exit(103);
}
return frequency;
that you assign in the caller.
This statement looks suspect (where you say "Here I allocated 1000 pointers for my table"):
table = (char**)calloc(MAX_SIZE + 1, sizeof(char));
That doesn't look like an allocation of pointers, but an allocation of a char buffer.
Perhaps you mean:
table = (char**)calloc(MAX_SIZE + 1, sizeof(char*));

Resources