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
Related
I am playing around with a series of functions that can be used to instantiate and add to a dynamically allocated array of strings in the C language. The pointer to a pointer for the array is contained in a struct along with related metadata. I have developed a function titled init_string_vector to instantiate the vector, another function titled push_string_vectorthat pushes strings to the end of the vector, free_string_vector to free all memory, and insert_string_vector which should allow a user to add data to any index in the vector, and not just the end of the vector such as would occur with the push_string_vector function.
The insert_string_vector function should check the string and ensure it has a null terminator (i.e. "\0"). If it does not have a null terminator, the function should add the terminator. Then, the function should check the allocated memory to ensure it is adequate, and if it is not, add the necessary memory with realloc. Finally with the memmove function, it should move everything to the right of the user defined index by one index, and then insert the string to the now blank previously occupied index. I can get everything in the function to work, but it appears that it is not allocating new memory, when it shifts everything one index to the right, and I can not figure out why. My series of functions are listed below. Any help would be appreicated.
typedef struct
{
char **vector;
size_t active_length;
size_t allocated_length;
size_t num_bytes;
} StringVector;
// --------------------------------------------------------------------------------
StringVector init_string_vector(size_t length) {
StringVector vec;
char **ptr = (char **)malloc(length * sizeof(char *));
if (ptr == NULL) {
printf("WARNING: Not enough available memory, exiting!\n");
free(ptr);
}
vec.num_bytes = sizeof(char *);
vec.active_length = 0;
vec.allocated_length = length;
vec.vector = ptr;
return vec;
}
// --------------------------------------------------------------------------------
int push_string_vector(StringVector *vec, char *value, size_t length) {
// Verify all values have null terminator
char new_value[length];
const char *test = ((char *)value) + length;
int cmp = strcmp(test, "\0");
if (cmp != 0) {
memcpy(new_value, value, length + 1);
memcpy(new_value + length, "\0", 1);
}
else memcpy(new_value, value, length);
// Begin push
value = strdup(new_value);
if (!value) return 0;
if (vec->active_length >= vec->allocated_length) {
size_t size = 2 * (sizeof(char *) * (vec->allocated_length));
char **resized = (char**)realloc(vec->vector, size);
if (resized == NULL) {
free(value);
return 0;
}
resized[vec->active_length] = value;
vec->vector = resized;
vec->allocated_length *= 2;
}
else {
vec->vector[vec->active_length] = value;
}
vec->active_length += 1;
return 1;
}
// --------------------------------------------------------------------------------
void free_string_vector(StringVector *vec) {
if (vec != NULL) {
for (size_t i = 0; i < vec->allocated_length; i++) {
free(vec->vector[i]);
}
free(vec->vector);
vec->vector = NULL;
vec->active_length = 0;
vec->allocated_length = 0;
vec->num_bytes = 0;
}
}
// --------------------------------------------------------------------------------
int insert_string_vector(StringVector *vec, char *value, size_t length, size_t index) {
// Verify all values have null terminator
char new_value[length];
const char *test = ((char *)value) + length;
int cmp = strcmp(test, "\0");
if (cmp != 0) {
memcpy(new_value, value, length + 1);
memcpy(new_value + length, "\0", 1);
length += 1;
}
else memcpy(new_value, value, length);
// Update vector size if necessary
if (vec->active_length >= vec->allocated_length) {
size_t size = 2 * (sizeof(char *) * (vec->allocated_length));
char **resized = (char**)realloc(vec->vector, size);
if (resized == NULL) {
free(value);
return 0;
}
vec->vector = resized;
vec->allocated_length *= 2;
}
// Move appropriate portion of vector to the right and insert correct value
memmove(vec->vector[index + 1], vec->vector[index], sizeof(char *));
vec->vector[index] = value;
vec->active_length += 1;
return 1;
}
int main() {
char a[6] = "Hello";
StringVector vec = init_string_vector(7);
push_string_vector(&vec, a, 6);
char b[7] = "World!";
push_string_vector(&vec, b, 7);
char c[5] = "Goof";
push_string_vector(&vec, c, 5);
char d[8] = "Goodbye";
insert_string_vector(&vec, d, 8, 1);
// - It appears to successfully move everything after index 1
// to the right by one index and also add the string "Goodbye"
// to the vector, but then throws a segmentation error fault.
for (size_t i = 0; i < vec.active_length; i++) {
printf("%s\n", vec.vector[i]);
}
}
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.
So I have an double char point guess and I have already malloc space for it and I have realloc for extra characters when enetered to get the right amount of memory allocated. The issue I'm having is that it segfaults whenever it hit *guess[i] = input and I cant figure out why ifI pass it \n from stdin it works and passes through the for loop but whenever there are more than one character from stdin it segfaults
Heres the for loop and malloc prior to it
char input;
guess = (char**) malloc(1*sizeof(char));
for(int i = 0; input != '\n'; i++)
{
input = getc(stdin);
lengthG += 1;
*guess =(char *) realloc(*guess, lengthG * sizeof(char));
*guess[i] = input;
}
And heres the whole function
int fund_check_input(char *val, char **guess)
{
size_t lengthV = 0;
size_t lengthG = 0;
for(int i = 0; val[i] != '\0'; i++)
{
if(lengthV < 4)
{
if(val[i] < 48 || val[i] > 57)
return -1;
else
lengthV += 1;
}
else
return -1;
}
char input;
guess = (char**) malloc(1*sizeof(char));
for(int i = 0; input != '\n'; i++)
{
input = getc(stdin);
lengthG += 1;
*guess =(char *) realloc(*guess, lengthG * sizeof(char));
*guess[i] = input;
}
printf("%s\n", "hey");
if(lengthG != lengthV)
return 0;
else
{
for(int i = 0; *guess[i] != '\0'; i++)
{
if(val[i] != *guess[i])
return 0;
}
}
return 1;
}
I think that I am allocating enough memory because when I increase the amount being realloc'd it still segfaults, so I am not entirely sure what is happening.
Here
guess = (char**) malloc(1*sizeof(char));
^^^^^
you only assign memory for 1 char.
However, it seems you want room for a pointer-to-char.
Did you intend to do:
guess = (char**) malloc(1*sizeof(char*));
^
Also notice
that the type cast is not needed in C.
that guess = malloc(1*sizeof *guess); is in general a better form as you avoid typos like the one you did above. (the 1* can be deleted as well)
That said, consider what the value of *guess is after fixing the above error. You need to make sure it's properly initialized before calling realloc
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.
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*));