bool check(const char *word)
{
int length = strlen(word);
//malloc size of char times length of word plus \0
char *lower_case = malloc(sizeof(char) * (length + 1));
lower_case[length + 1] = '\0';
//change characters to lowercase
for (int i = 0; i < length; i++)
{
lower_case[i] = tolower(word[i]);
}
//generate int hash
int index = generate_hash(lower_case);
node_ptr trav = hashtable[index];
while (trav != NULL)
{
if (strcmp(trav->word, lower_case) == 0)
{
return true;
}
trav = trav -> next;
}
free(lower_case);
return false;
}
I got 27 bytes of memory leaked from a Valgrind test; how to free it?
lower_case[length + 1] = '\0'; writes out of bounds, change to [length].
You are missing #include <stdlib.h> and other necessary includes.
You create a memory leak each time you execute return true;.
Never hide pointers behind typedefs, as taught by crap classes like CS-50.
You should be able to fix the code along the lines of this:
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdbool.h>
bool check (const char *word)
{
size_t length = strlen(word);
char* lower_case = malloc(length + 1);
if(lower_case == NULL)
{
return false;
}
//change characters to lowercase
for (size_t i = 0; i < length; i++)
{
lower_case[i] = tolower(word[i]);
}
lower_case[length] = '\0';
//generate int hash
int index = generate_hash(lower_case);
bool result = false;
for(const node* trav = hashtable[index]; trav!=NULL; trav=trav->next)
{
if (strcmp(trav->word, lower_case) == 0)
{
result = true;
break;
}
}
free(lower_case);
return result;
}
The type node_ptr needs to be changed into node without hidden pointers.
There's an out of bounds access immediately after malloc.
Here, you're accessing out of bounds:
lower_case[length + 1] = '\0';
It should be:
lower_case[length] = '\0';
It's also a sensible idea to check if malloc failed, too!
As noted in comments, there's also a case when memory leak can happen when returning from inside the loop. You need to free there:
if (strcmp(trav->word, lower_case) == 0)
{
free(lower_case);
return true;
}
Related
My reallocation does not work (Segmentation fault for 11.element), I would like to enlarge the array twice, the length of the column is constant according to the first input.I would like to allocate in function.
In the function vztvorPole I allocate an array of 10 rows and x columns.
char vytvorPole(char ***grid, int nrows, int ncols)
{
*grid = malloc( sizeof(*grid)*nrows);
if (*grid == NULL)
{
printf("ERROR\n");
return 1;
}
for(int i=0;i<nrows;i++)
{
(*grid)[i]=(char *) malloc (ncols*sizeof(*grid));
if((*grid)[i] == NULL)
{
printf("ERROR\n");
return 1;
}
}
return 0;
}
char realokuj(char ***grid, int nrows, int ncols)
{
char **docasne;
docasne = (char**)realloc (*grid, nrows*sizeof(*grid));
for(int i=nrows/2;i<nrows;i++)
{
(docasne)[i]=(char *) malloc (ncols*sizeof(*grid));
}
*grid = docasne;
}
int main (void)
{
char **diagonaly;
int rDiagonaly = 10;
int cDiagonaly = -1;
char *str = NULL;
size_t capacity = 0;
int first = 1;
int nr = 0;
printf("Vypln:\n");
while ( getline (&str, &capacity, stdin) != -1)
{
if(str[0] == '\n')
break;
if (first)
{
cDiagonaly = strlen (str);
vytvorPole(&diagonaly, rDiagonaly, cDiagonaly);
first = 0;
}
if (nr==rDiagonaly)
{
rDiagonaly *= 2;
realokuj(&diagonaly, rDiagonaly, cDiagonaly);
}
strcpy(diagonaly[nr],str);
nr++;
}
}
Your code is a bit more complicated than needed.
If you initialize diagnonaly (e.g. char **diagnoaly = NULL;), you can eliminate vytvorPole and just use realokuj. That is, if you also do: int rDiagonaly = 0;
That's because realloc will handle a NULL pointer just fine (i.e. it's equivalent to malloc in that case).
And, you don't need to do:
(docasne)[i]=(char *) malloc (ncols*sizeof(*grid));
in the subfunction.
It's better to use strdup in main. If we do that, we don't need cDiagonaly at all. And, we can have strings of varying lengths.
Passing a triple star pointer (e.g. char ***grid) has issues. You could just pass it as char ** and use return to update the value since you don't really use the existing return.
But, this can really be done from main without a separate function.
While it may be possible to fix your existing code, it really should be simplified:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(void)
{
#if 0
char **diagonaly;
int rDiagonaly = 10;
#else
char **grid = NULL;
int rmax = 0;
#endif
#if 0
int cDiagonaly = -1;
#endif
char *str = NULL;
size_t capacity = 0;
#if 0
int first = 1;
#endif
int nr = 0;
printf("Vypln:\n");
while (getline(&str,&capacity,stdin) != -1) {
if (str[0] == '\n')
break;
if (nr == rmax) {
rmax += 100;
grid = realloc(grid,sizeof(*grid) * (rmax + 1));
if (grid == NULL) {
perror("realloc");
exit(1);
}
// this is similar to what you did, but it's not necessary because
// of "grid[nr] = NULL;" below
#if 0
for (int idx = nr; idx < rmax; ++idx)
grid[idx] = NULL;
#endif
}
grid[nr++] = strdup(str);
grid[nr] = NULL;
}
return 0;
}
Here's the cleaned up version [without the cpp conditionals]:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(void)
{
char **grid = NULL;
int rmax = 0;
char *str = NULL;
size_t capacity = 0;
int nr = 0;
printf("Vypln:\n");
while (getline(&str,&capacity,stdin) != -1) {
if (str[0] == '\n')
break;
if (nr == rmax) {
rmax += 100;
grid = realloc(grid,sizeof(*grid) * (rmax + 1));
if (grid == NULL) {
perror("realloc");
exit(1);
}
}
grid[nr++] = strdup(str);
grid[nr] = NULL;
}
return 0;
}
Is something like that okay?
while ( getline (&str, &capacity, stdin) != -1)
{
if(str[0] == '\n')
break;
if (first)
{
cDiagonaly = strlen (str);
diagonaly = (char**) malloc(sizeof(*diagonaly)*rDiagonaly);
if (nr==rDiagonaly)
{
rDiagonaly *= 2;
docasne = (char**)realloc (diagonaly, rDiagonaly*sizeof(*diagonaly));
diagonaly=docasne;
}
diagonaly[nr]=(char*) malloc (cDiagonaly*sizeof(**diagonaly));
strcpy(diagonaly[nr],str);
nr++;
}
I need to dynamically append a char to a string, so I'm using realloc() to add more memory as I need it.
I'm new to C (coming from Python) so I've been reading a lot and this was the best I could do:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void append_to(char *array, char value) {
size_t buffer = (strlen(array) * sizeof(char)) + sizeof(char);
char *new_array = realloc(array, buffer);
if (new_array == NULL) {
printf("CRITICAL ERROR\n");
exit(-1);
}
array = new_array;
int position = strlen(array);
array[position] = value;
}
int main() {
char *list = malloc(sizeof(char));
for (int i = 1; i < 26; i++){
append_to(list, 'a');
printf("%d -> %s\n", i, list);
}
}
This is just an example to showcase the issue. The code runs flawlessly until iteration 24, see below:
1 -> a
2 -> aa
[...] //omitted
23 -> aaaaaaaaaaaaaaaaaaaaaaa
24 -> aaaaaaaaaaaaaaaaaaaaaaaa
25 ->
What am I missing?
First you forget to add another NUL char at the end of your c-string.
Second, realloc may change the memory location of the data, but you passed the list as value, so the relocation is not visible in the case of data relocation.
That should lokks like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void append_to(char **array, char value) { // pass pointer's address
size_t buffer = (strlen(*array) * sizeof(char)) + sizeof(char) + sizeof(char); // one more to tackle the end of the string
char *new_array = realloc(*array, buffer);
if (new_array == NULL) {
printf("CRITICAL ERROR\n");
exit(-1);
}
*array = new_array;
int position = strlen(*array);
(*array)[position] = value;
(*array)[position+1] = 0; // end of string
}
int main() {
char *list = malloc(sizeof(char));
list[0] = 0; // end of string
for (int i = 1; i < 26; i++){
append_to(&list, 'a'); // pass address of array so that it can be changed by the call
printf("%d -> %s\n", i, list);
}
free(list); // always explicitly free unused resources
}
You didn't receive array as a double pointer, so you can't reassign the caller's pointer when realloc has to move the allocation.
To fix,
// Receive double pointer
void append_to(char **array, char value) {
// Add dereferencing as needed
size_t buffer = (strlen(*array) + 2) * sizeof(char);
char *new_array = realloc(*array, buffer);
if (new_array == NULL) {
printf("CRITICAL ERROR\n");
exit(-1);
}
*array = new_array;
int position = strlen(*array);
array[0][position] = value;
array[0][position+1] = '\0'; // Explicitly NUL terminate, don't assume new memory is zeroed
}
int main() {
char *list = malloc(sizeof(char));
for (int i = 1; i < 26; i++){
append_to(&list, 'a'); // Pass address of list
printf("%d -> %s\n", i, list);
}
}
EDIT: I should add how I have this all set up. The struct definition and prototypes are in mystring.h. The function definitions are in mystring.c. The main is in mystringtest.c. For mystring.c and mystringtest.c, I have #include "mystring.h" at the top. I'm compiling like gcc -o test.exe mystring.c mystringtest.c. Not sure if any of that matters, but I'm new with C so I'm just trying to include everything.
I have a good deal of experience with Java but am pretty new to C. I imagine this is related to pointers and memory but I'm totally at a loss here for what's going on. Here's my code:
typedef struct {
char *chars;
int length;
int maxSize;
} String;
int main() {
char *a;
a = readline();
String *s = newString(a);
int b = length(s);
printf("length is %d \n", b);
}
I run the program and enter "hello" (as prompted by readline()). I've stepped through the program and after length(s), s->chars is still a pointer to the array of chars 'hello'. After the print statement, s->chars becomes a pointer to the array of chars 'Length is %d \n'. I'm totally at a loss for what I'm doing wrong. I'm working on a virtual machine if that matters at all. Any help is greatly appreciated. I'll give the code for newString and length too.
int length(String *s) {
char *temp = s->chars;
char b = *temp;
int count;
if (b == '\0') { count = 0; }
else { count = 1; }
while (b != '\0') {
b = *(temp+count);
count++;
}
return count;
}
String *newString(char *s) {
String st;
st.length = 20;
st.maxSize = MAXCHAR;
char *temp = malloc(20 * sizeof(char));
char b = *s;
int count = 0;
while (b != '\0') {
*(temp + count) = b;
count++;
b = *(s+count);
if (count == st.maxSize) { break; }
if (count == st.length) {
st.length = st.length + 20;
temp = realloc(temp, st.length * sizeof(char));
}
}
st.chars = temp;
return &st;
}
String *newString(char *s) {
String st;
...
return &st;
}
You are returning a pointer to a local variable. After newString returns, the local variable no longer exists, so you have a dangling pointer.
Either allocate st with malloc, or return it by value.
you must null terminate the string after the while loop, you have not left space for the null terminator. Also I don't see why you need to realloc
//using strlen will eliminate the need for realloc, +1 is for the null terminator
int len = strlen(s)
char *temp = malloc((len * sizeof(char)) +1);
//null terminate
*(temp+count) = '\0';
st.chars = temp;
I am learning C, and am have a problem finding out how i can free my malloc()'s.
The program runs correctly.. but im Using valgrind and it is coming up with 8 allocs and 5 frees. I need to be able to free 3 more. I commented where I believe which I am not freeing but I am not sure of a solution.
Is there a way I can free up those allocs, or do I need to consider re-writing the tokenizer()?
Here is the code to the whole file.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char *substr(const char *s, int from, int nchars) {
char *result = (char *) malloc((nchars * sizeof(char))+1);
strncpy(result, s+from, nchars);
return result;
}
/**
Extracts white-space separated tokens from s.
#param s A string containing 0 or more tokens.
#param ntokens The number of tokens found in s.
#return A pointer to a list of tokens. The list and tokens must be freed
by the caller.
*/
char **tokenize(const char *s, int *ntokens) {
int fromIndex = 0;
int toIndex = 0;
char **list;
int finalCount = *ntokens;
int count = 0;
list = malloc(*ntokens * sizeof(char*));
while ( count < finalCount) {
char *m = strchr(s,' ');
toIndex = m - s;
if(toIndex >= 0) {
list[count] = substr(s,fromIndex,toIndex); // This substr() gets free'ed from main()
s = substr(s, toIndex+1, strlen(s)); // I believe This is where I am making extra mallocs that are not being freed
count++;
} else {
list[count] = substr(s,fromIndex,strlen(s)); // This substr() gets free'ed from main()
count++;
}
}
return list;
}
int main(int argc, char **argv) {
char **list;
char *string = "terrific radiant humble pig";
int count = 4; // Hard-Coded
list = tokenize(string, &count);
for (int i=0;i<count;i++) {
printf("list[%d] = %s\n", i, list[i]);
}
// Free mallocs()'s
for (int i=0;i<count;i++) {
free(list[i]);
}
// Free List
free(list);
return 0;
}
You don't need substr s everytime after getting one token. This is too wasteful, in terms of both time and spape. You can just change the value of s to make it point to the string you need.
//s = substr(s, toIndex+1, strlen(s)); // You don't need have to generate a new string
s = s + toIndex + 1;//You can just change the value of s to make it point to the string you need
The problem is exactly where you thought it was!
Luckily in c is very easy to move the point , at which a string, you do not need to call again substr; because of pointers ;-)
// s = substr(s, toIndex+1, strlen(s));
s += toIndex+1;
A simple workaround I can think of, by just storing the current value of s in another pointer before you overwrite. And also make sure not to free the first value of s got directly as the parameter to tokenize().
char **tokenize(const char *s, int *ntokens) {
int fromIndex = 0;
int toIndex = 0;
char **list;
int finalCount = *ntokens;
int count = 0;
bool firstTime = true; // Use this to make sure you do not free up the memory for the initial s passed as the function arg
list = malloc(*ntokens * sizeof(char*));
while ( count < finalCount) {
char *m = strchr(s,' ');
toIndex = m - s;
if(toIndex >= 0) {
const char* previous_s = s; // Store the current value of s
list[count] = substr(s,fromIndex,toIndex); // This substr() gets free'ed from main()
s = substr(previous_s, toIndex+1, strlen(previous_s));
if (!firstTime)
{
free(previous_s); // Since we're done with the previous_s, we can free up the memory
}
firstTime = false;
count++;
} else {
list[count] = substr(s,fromIndex,strlen(s)); // This substr() gets free'ed from main()
count++;
}
}
if (!firstTime)
{
free(s); // There could be a block allocated last time which needs to be freed as well
}
return list;
}
Based on my previous post, I came up with the following code. I'm sure there is a better way of doing it. I'm wondering, what would that be?
It does split the string if greater than max chars OR if # is found. Any ideas would be appreciated!
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct my_struct {
char *str;
};
int main () {
struct my_struct *struc;
int max = 5;
char *tmp = "Hello World#Foo Bar In here#Bar Foo dot com#here#there";
struc = malloc (20 * sizeof (struct my_struct));
int strIdx = 0, offSet = 0;
char *p = tmp;
char *tmpChar = malloc (strlen (tmp) + 1), *save;
save = tmpChar;
while (*p != '\0') {
if (offSet < max) {
offSet++;
if (*p == '#') {
if (offSet != 1) {
*tmpChar = '\0';
struc[strIdx++].str = strndup (save, max);
save = tmpChar;
}
offSet = 0;
} else
*tmpChar++ = *p;
} else { // max
offSet = 0;
*tmpChar = '\0';
struc[strIdx++].str = strndup (save, max);
save = tmpChar;
continue;
}
p++;
}
struc[strIdx++].str = strndup (save, max); // last 'save'
for (strIdx = 0; strIdx < 11; strIdx++)
printf ("%s\n", struc[strIdx].str);
for (strIdx = 0; strIdx < 11; strIdx++)
free (struc[strIdx].str);
free (struc);
return 0;
}
Output at 5 chars max:
Hello
Worl
d
Foo B
ar In
here
Bar F
oo do
t com
here
there
Alright, I'll take a crack at it. First, let me say that my formatting changes were for me. If you don't like lonely {s, that's fine.
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 5
struct string_bin
{
char *str;
};
int main ()
{
struct string_bin *strings;
char *tmp = "Hello World#Foo Bar In here#Bar Foo dot com#here#there";
char *p = tmp;
strings = malloc (20 * sizeof (struct string_bin));
memset(strings, 0, 20 * sizeof (struct string_bin));
int strIdx = 0, offset = 0;
char *cursor, *save;
strings[strIdx].str = malloc(MAX+1);
save = strings[strIdx].str;
while (*p != '\0')
{
if (offset < MAX && *p != '#')
{
*(save++) = *(p++);
offset++;
continue;
}
else if (*p == '#')
*p++;
offset = 0;
*save = '\0';
strings[++strIdx].str = malloc(MAX+1);
save = strings[strIdx].str;
}
*save = '\0';
for (strIdx = 0; strings[strIdx].str != NULL; strIdx++)
{
printf ("%s\n", strings[strIdx].str);
free (strings[strIdx].str);
}
free (strings);
return 0;
}
The big change is that I got rid of your strdup calls. Instead, I stuffed the string directly into its destination buffer. I also made more calls to malloc for individual string buffers. That lets you not know the length of the input string ahead of time at the cost of a few extra allocations.