Frequency array dynamic allocation using C - 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*));

Related

Problem with c with dynamically allocating an array

#include <stdio.h>
#include <stdlib.h>
void input_all(char* array)
{
int c = 0;
int increse = 20;
int number_of_char = 0;
for (int increment = 0; (c = getchar()) != '\n'; increment++)
{
++number_of_char;
if (number_of_char % 10)
{
array = (char*)realloc(array, increse + sizeof(char));
if (array == NULL)
{
printf("not alocated!");
exit(22);
}
increse += 10;
}
array[increment] = c;
}
printf("%s\n", array);
}
int main(void)
{
char* array = (char*)malloc(10);
if (array == NULL)
{
printf("not alocated\n");
exit(33);
}
input_all(array);
printf("%s\n", array);
return 0;
}
So what I'am trying to do is to fill up "array" with getchar. When I try to print it out I get some garbage values at the end (most of the time). I think the problem is that I'am giving out to much space to "array" with realloc but I have no idea how to fix it. I also tried placing all the sizes to 1 in malloc and realloc and increse so that whenever i get a charcter the size of "array" increses but it still did not work.
Anyone have any idea how ot fix it?
Thanks in advance!
array must be null terminated, otherwise printf and other c-string functions don't know where the end of the string is at.
realloc may not return the same address (although that's not an issue on your PC), you have to use the address of pointer.
You can allocate the whole array realloc. If subsequent realloc fails then you don't necessarily have to exit, you can print error and return the string which was already allocated.
void input_all(char** parray)
{
char* arr = NULL;
int size = 0, i = 0;
while(1)
{
int c = fgetc(stdin);
if (c == '\n' || c == EOF)
break;
if (i == size)
{
size += 10;
char* temp = realloc(arr, size + 1);
if (temp == NULL) { printf("realloc failed\n"); break; }
arr = temp;
}
arr[i++] = (char)c;
}
if(arr)
arr[i] = '\0'; //<- don't forget to terminate the string with 0
*parray = arr;
}
int main(void)
{
char* array = NULL;
input_all(&array);
if (!array)
return 1;
printf("%s\n", array);
free(array);
return 0;
}

How can I change an array of string pointers in another function?

I have been trying to figure out how to modify an array of char pointers but no matter what I do there appears to be no change below are the three arrays I'm trying to change including the call to the function I'm using.
char*cm1[5];
char*cm2[5];
char*cm3[5];
setupCommands(&cm1,commands,file,0);
setupCommands(&cm2,commands,file,1);
setupCommands(&cm3,commands,file,2);
The code below is the function itself.I was thinking that maybe it involves a double pointer but if I try *cmd to change the array I get a segmentation fault.
void setupCommands(char **cmd[], char* commands[],char file[],int index){
char str1[255];
strcpy(str1,commands[index]);
char newString [5][255];
int j = 0;
int ctr = 0;
int i;
//printf("str1 %s\n" ,str1);
for(i = 0; i <= strlen(str1); i++){
if(str1[i] == ' '|| str1[i] =='\0'){
newString[ctr][j] = '\0';
ctr++;//next row
j=0;// for next word, init index to 0
}else{
newString[ctr][j]=str1[i];
j++;
}
}
for(i = 0; i < ctr; i++){
//printf(" test2 %s \n", newString[i]);
cmd[i] = newString[i];
//printf(" test2 %d %s \n", i,cmd[i]);
}
//printf("index %d", i);
cmd[i]= file;
cmd[i + 1] = NULL;
//execvp(cmd[0],cmd);
//cmd
}
There are a few issues with your code:
you are trying to return references to the local 'char newString [5][255]' when the function exits. In simple worlds - never return anything locally allocated on the stack. This is the reason you are getting the segmentation fault.
char **cmd[] must be declared char *cmd[] - even though you will get a warning from the compiler assignment from incompatible pointer type, the code would run and execute correctly(essentially **cmd[] would do the same work as *cmd[], even though it's not of correct type) if you didn't return references to the local object;
Easy and simple optimization is just to remove the array str1 and directly operate on the array commands.
Apart from this simple optimization I have changed your code to overcome the segmentation fault, by allocating on the heap, instead on stack(will live until the program terminates) the multidimensional array, and I also calculate it's size so I will know how much memory to allocate. Now it's safe to return references to it.
Note that more optimizations could be made, but for the sake of the simplicity this is the bare minimal for this code to work.
int setupCommands(char *cmd[], char *commands[], char file[], int index)
{
int j = 0;
int ctr = 0;
int i = 0;
int rows = 0;
int cols = 0;
char **newString = NULL;
while(commands[index][i])
{
if (commands[index][i] == ' ')
{
++rows;
}
++i;
}
++rows;
cols = strlen(commands[index]) + 1;
newString = malloc(rows * sizeof(*newString));
if (newString == NULL)
{
return -1;
}
for (i = 0; i < rows; ++i)
{
newString[i] = malloc(cols * sizeof(*newString));
if (newString[i] == NULL)
{
return -1;
}
}
for(i = 0; i <= strlen(commands[index]); i++){
if(commands[index][i] == ' '|| commands[index][i] =='\0'){
newString[ctr][j] = '\0';
ctr++;//next row
j=0;// for next word, init index to 0
}else{
newString[ctr][j]=commands[index][i];
j++;
}
}
for(i = 0; i < ctr; i++){
cmd[i] = newString[i];
}
cmd[i]= file;
cmd[i + 1] = NULL;
return 0;
}
First of all - being the three stars pointer programmer is not good :)
You assign it with pointer to the local variable which is not longer available after the function return
But if you still want the three stars pointers:
char **cm1;
char **cm2;
char **cm3;
setupCommands(&cm1,commands,file,0);
setupCommands(&cm2,commands,file,1);
setupCommands(&cm3,commands,file,2);
#define MAXWORD 256
int setupCommands(char ***cmd, const char *commands,const char *file,int index){
char str1[255];
strcpy(str1,commands[index]);
int j = 0;
int ctr = 0;
int i;
//printf("str1 %s\n" ,str1);
*cmd = malloc(sizeof(char *));
**cmd = malloc(MAXWORD);
if(!*cmd || !**cmd)
{
/* do spmething if mallocs failed*/
return -1;
}
for(i = 0; i <= strlen(str1); i++){
if(str1[i] == ' '|| str1[i] =='\0'){
(*cmd)[ctr][j] = '\0';
ctr++;//next row
*cmd = realloc((ctr + 1) * sizeof(int));
(*cmd)[ctr] = malloc(MAXWORD);
if(!*cmd || !*cmd[ctr])
{
/* do spmething if mallocs failed*/
return -1;
}
j=0;// for next word, init index to 0
}else{
(*cmd)[ctr][j]=str1[i];
j++;
}
}
*cmd = realloc(sizeof(char *) * ctr + 2)
(*cmd)[ctr - 2] = malloc(MAX);
if(!*cmd || !*cmd[ctr - 2])
{
/* do spmething if mallocs failed*/
return -1;
}
strcpy((*cmd)[ctr - 2], file);
(*cmd)[ctr - 1] = NULL;
return 0;
//execvp(cmd[0],cmd);
//cmd
}
you can improve many things (for example do not realloc every time but in the larger chunks) and I did not change anything in your code logic.

Trouble printing an array of strings after realloc?

The code below reads characters and splits them into C-style strings when a delimiter is encountered, then it stores the words (white-space-separated sequences of characters) in string array till a sentinel is encountered; updates size of string array:
#include <stdio.h> // printf()
#include <stdlib.h> // malloc(); realloc()
#include <string.h> // strcmp()
#include <stddef.h> // size_t
void print_array(char* arr[ ], size_t size); // forward declaration to use in to_array()
char* get_word(char delimiter)
{
size_t size = 8;
size_t index = 0;
int c = 0;
char* word = 0;
char* expand_word = 0;
word = (char*) malloc(sizeof(char) * size);
if (word == NULL)
{
perror("get_word::bad malloc!\n");
exit(-1);
}
while ((c = getchar()) != EOF && c != delimiter && c != '\n')
{
if (index >= size)
{
size *= 2;
expand_word = (char*) realloc(word, sizeof(char) * size);
if (expand_word == NULL)
{
perror("get_word::bad realloc!\n");
exit(-1);
}
word = expand_word;
}
word[index++] = c;
}
word[index] = 0;
return word;
}
//-------------------------------------------------------------------------------------
void to_array(char* arr[ ], size_t* size, char* sentinel)
{
size_t index = 0;
char* word = 0;
char** expand_arr = 0;
char delimiter = ' ';
while ((word = get_word(delimiter)) && strcmp(word, sentinel) != 0)
{
if (index >= (*size))
{
(*size) *= 2;
expand_arr = (char**) realloc(arr, sizeof(char*) * (*size));
if (expand_arr == NULL)
{
perror("to_array::bad realloc!\n");
exit(-1);
}
arr = expand_arr;
}
arr[index++] = word;
}
(*size) = index;
// print_array(arr, *size); // <---- here, all words printed OK.
// getchar();
}
//-------------------------------------------------------------------------------------
void print_array(char* arr[ ], size_t size)
{
size_t i = 0;
printf("{ ");
for (i; i < size; ++i)
{
printf("%s", arr[i]);
if (i < size - 1)
{
printf(", ");
}
}
printf(" }\n");
}
//-------------------------------------------------------------------------------------
int main()
{
size_t size = 4;
char** arr = 0;
char* sentinel = "quit";
arr = (char**) malloc(sizeof(char*) * size);
if (arr == NULL)
{
perror("array of strings::bad malloc!\n");
exit(-1);
}
printf("Type a sentence and get each word as an array element:\n");
to_array(arr, &size, sentinel);
printf("Words:\n");
print_array(arr, size); // <--------- here, error!
getchar();
}
When trying to print the string array, I get:
Access violation reading location 0xcd007361.
Why I can't print the strings in arr at the end?
P.S.: I guess that the problem comes from the pointer arithmetic and the reallocation of the char** arr within function to_array(). (If previous right) I'm not sure what would be the standard way to deal with it?
Problem: the first parameter in void to_array(), i.e. char* arr[ ] passes a copy of a pointer to array of char. Every change on the pointer made inside the function does not affect the actual pointer to char array outside, specifically the function realloc() may move the initial memory block to a new location, which would invalidate the pointer passed as first parameter.
Solution: either to modify the function void to_array() to return the modified arr, or to modify the first parameter of the function to char** arr[ ]. The latter was chosen and the modified code looks like this:
void to_array(char** arr[ ], size_t* size, char* quit)
{
size_t index = 0;
char* word = 0;
char** expand_arr = 0;
char sentinel = ' ';
while ((word = get_word(sentinel)) && strcmp(word, quit) != 0)
{
if (index >= (*size))
{
(*size) *= 2;
expand_arr = (char**) realloc((*arr), sizeof(char*) * (*size));
if (expand_arr == NULL)
{
perror("to_array::bad realloc!\n");
exit(-1);
}
(*arr) = expand_arr;
}
(*arr)[index++] = word;
}
(*size) = index;
}
then the function call must be done as:
to_array(&arr, &size, quit);

Deallocation of memory in arrays

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.

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

Resources