Hi so I am creating a program that uses a hash to store words and their number of occurrences from a text file. That works as intended. The issue I am having comes from freeing the allocated memory.
Here is my hash
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#include"hash.h"
/*
struct listnode{
char * word;
int count;
};
*/
void hashCreate(struct listnode * hashTable[], int size){
int i;
for(i=0;i<size;i++){
hashTable[i]=(struct listnode *)malloc(sizeof(struct listnode));
hashTable[i]->count=0;
}
}
int hash(char * data, int size) {
unsigned long hash = 5381;
char * p;
for (p = data; *p != '\0'; ++p) {
hash = (hash * 33) + *p;
}
return (int)(hash % size);
}
void hashAdd(char * data, struct listnode * hashTable[], int size){
int key=hash(data, size);
hashTable[key]->word=strdup(data);
hashTable[key]->count+=1;
}
void hashPrint(struct listnode * hashTable[], int size){
int i;
for(i=0;i<size;i++){
if(hashTable[i]->count!=0)
printf("%s: %d \n",hashTable[i]->word,hashTable[i]->count);
}
}
void hashDelete(struct listnode * hashTable[],int size){
int i;
for(i=0;i<size;i++){
free(hashTable[i]->word);
free(hashTable[i]);
}
}
This is what uses it
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#include"hash.h"
/*
int hash(char * data, int size) {
unsigned long hash = 5381;
char * p;
for (p = data; *p != '\0'; ++p) {
hash = (hash * 33) + *p;
}
return (int)(hash % size);
}
*/
#define SIZE 1500
void removePunct(char * str);
void fileRead(char * filename);
struct listnode * hashTable[1500];
int main(int argc, char ** argv){
int i;
if(argc<2)
fprintf(stderr,"Enter filename \n");
hashCreate(hashTable, SIZE);
for(i=1; i<argc; i++){
fileRead(argv[i]);
}
hashPrint(hashTable,SIZE);
hashDelete(hashTable, SIZE);
return 0;
}
void fileRead(char * filename){
FILE * file = fopen(filename,"r");
char word[80];
if(!file){
fprintf(stderr,"Error opening file \n");
return;
}
while(fscanf(file, "%s", word)==1){
removePunct(word);
hashAdd(word,hashTable,SIZE);
}
fclose(file);
}
void removePunct(char * str){
int i,p=0;
for(i=0; i<strlen(str);i++){
if(isalpha(str[i]) || str[i]==' '){
str[p]=tolower(str[i]);
p++;
}
}
str[p]='\0';
}
In my hashDelete function the strings are not being freed which is causing a memory leak. I tested it by freeing the string within the hashAdd function and there were no memory leaks but there were also no strings being printed. Im unable to find the issue that is not letting me free all my memory. Any help would be appreciated.
In this code
void hashAdd(char * data, struct listnode * hashTable[], int size){
int key=hash(data, size);
hashTable[key]->word=strdup(data);
hashTable[key]->count+=1;
}
you use strdup to get a new string (malloc'ed by strdup). If you already have done that once for a given key you'll leak memory.
So you need a check like:
if (hashTable[key]->word == NULL) hashTable[key]->word=strdup(data);
However, that requires that you initialize wordto NULL when creating the table.
Of topic: Normally, you will however need to handle identical key values with some extra code. The data value resulting in that key may or may not be the same as the word already stored. Something you should check. If they are identical, you can increment count. If they differ, you'll have to have a method for storing two different words with identical key values.
It could look something like:
void hashAdd(char * data, struct listnode * hashTable[], int size){
int key=hash(data, size);
if (hashTable[key]->word == NULL) {
// First time with this key
hashTable[key]->word=strdup(data);
hashTable[key]->count+=1;
} else {
// Key already used once
if (strcmp(data, hashTable[key]->word) == 0) {
// Same word
hashTable[key]->count+=1;
} else {
// Different word
// ...
// Add code for storing this word in another location
// ...
}
}
}
Related
This simplified version of the program has the task of storing a char string in an array. If the product with the given name is already occupied, I don't store it, otherwise I use malloc to allocate space for the chain.
But I'm getting a segmentation fault and I can't find the fault
Complet program https://onecompiler.com/c/3yqnk3e5s
struct product{
int *regal;
char *name;
}product;
struct product allocList(struct product **list, int *alloc)
{
*list = (struct product*) malloc(sizeof(struct product)*(*alloc));
(*list)->regal = calloc(100, sizeof(int));
}
int isInList(struct product **list, int *listSize, char *item, int *itemIndex)
{
for(int i=0; i< *listSize; i++)
if(! strcmp(item, list[i]->name))
{
(*itemIndex) = i;
return 1;
}
return 0;
}
int insert(struct product **list, int *alloc, int *listSize, char *item, int regalIndex)
{
int itemIndex = 0;
if(isInList(*(&list), *(&listSize), item, &itemIndex))
return 0;
list[(*listSize)]->name = (char*) malloc(sizeof(char)*(strlen(item)+1));
strcpy(list[(*listSize)]->name, item);
(*listSize)++;
return 1;
}
int main()
{
struct product *list = NULL; int listAlloc = 2000; int listSize = 0; allocList(&list, &listAlloc);
char *str = "abcd"; char *str1 = "bcd";
insert(&list, &listAlloc, &listSize, str, 1);
insert(&list, &listAlloc, &listSize, str, 1);
insert(&list, &listAlloc, &listSize, str1, 1);
return 0;
}
Your program segfaults in insert() on the first line and when you fix that the following line:
list[(*listSize)]->name = (char*) malloc(sizeof(char)*(strlen(item)+1));
strcpy(list[(*listSize)]->name, item);
As list is of type struct product **list it means you deference whatever data is stored sizeof(list) * (*listSize) elements after list which is undefined behavior when *listList > 0. Instead you want to dereference list, then access a array element *listSize. I suggest you use strdup() instead of malloc() + strcpy():
(*list)[*listSize].name = strdup(item);
The next step would be to introduce a struct to hold your list implementation details, and pass that around instead of the double pointers.
Here is my problem: I have to make this program for school and I spent the last hour debugging and googling and haven't found an answer.
I have an array of structures in my main and I want to give that array to my function seteverythingup (by call by reference) because in this function a string I read from a file is split up, and I want to write it into the structure but I always get a SIGSEV error when strcpy with the struct array.
This is my main:
int main(int argc, char *argv[])
{
FILE* datei;
int size = 10;
int used = 0;
char line[1000];
struct raeume *arr = (raeume *) malloc(size * sizeof(raeume*));
if(arr == NULL){
return 0;
}
if(argc < 2){
return 0;
}
datei = fopen(argv[1], "rt");
if(datei == NULL){
return 0;
}
fgets(line,sizeof(line),datei);
while(fgets(line,sizeof(line),datei)){
int l = strlen(line);
if(line[l-1] == '\n'){
line[l-1] = '\0';
}
seteverythingup(&line,arr,size,&used);
}
ausgabeunsortiert(arr,size);
fclose(datei);
return 0;
}
and this is my function:
void seteverythingup(char line[],struct raeume *arr[], int size,int used)
{
char *token,raumnummer[5],klasse[6];
int tische = 0;
const char c[2] = ";";
int i=0;
token = strtok(line, c);
strcpy(raumnummer,token);
while(token != NULL )
{
token = strtok(NULL, c);
if(i==0){
strcpy(klasse,token);
}else if(i==1){
sscanf(token,"%d",&tische);
}
i++;
}
managesize(&arr[size],&size,used);
strcpy(arr[used]->number,raumnummer);
strcpy(arr[used]->klasse,klasse);
arr[used]->tische = tische;
used++;
}
Edit: Since there is more confusion I wrote a short program that works out the part you are having trouble with.
#include <cstdlib>
struct raeume {
int foo;
int bar;
};
void seteverythingup(struct raeume *arr, size_t len) {
for (size_t i = 0; i < len; ++i) {
arr[i].foo = 42;
arr[i].bar = 53;
}
}
int main() {
const size_t size = 10;
struct raeume *arr = (struct raeume*) malloc(size * sizeof(struct raeume));
seteverythingup(arr, size);
return 0;
}
So basically the signature of your functions is somewhat odd. Malloc returns you a pointer to a memory location. So you really dont need a pointer to an array. Just pass the function the pointer you got from malloc and the function will be able to manipulate that region.
Original Answer:
malloc(size * sizeof(raeume*));
This is probably the part of the code that gives you a hard time. sizeof returns the size of a type. You ask sizeof how many bytes a pointer to you raeume struct requires. what you probably wanted to do is ask for the size of the struct itself and allocate size times space for that. So the correct call to malloc would be:
malloc(size * sizeof(struct raeume));
there are 4 .c/.h files. each having some global variables & structure variables. I got all the variables names from .map file . I extracted all in a two dimensional array/*array[](char type). now i want to pass sizeof each variables and address of it
Ok. If you need allocate dynamic memory in a variable, you need use a malloc function in "stdlib.h" and to read the file, you can store this into a linked list to process one by one.
Check the example...
We have a 'variables.map' in this semantic:
eua 40
brasil 30
paris 15
horse 8
Where the first column is the name (maximum 40 chars See struct prototype) of variable and the second is the size. (Note: is separate by line break '\n')
The program load the file into a linked list in memory and allocate the respective memory spaces (Check main()).
See the example program...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//MAP prototype
typedef struct map {
char name[40];
unsigned int size;
struct map *next;
} map;
//---
//Prototypes
void createList();
void insert(char[], int, map*);
void showList(map*);
unsigned int searchVariable(char[], map*);
void parseMapFile(char[]);
//---
//List, Linked list pointer
map *list_variables;
//---
//Main!
int main(int argc, const char * argv[])
{
//Create list!
createList();
//Parse the .Map file into struct
parseMapFile("/Users/gabriel/Documents/variables.map");
//Show linked list
//showList(list_variables);
//------
//Lets go now allocate the variables with the size in .map file
//Allocate space!
//Tipical types
int *eua = malloc(searchVariable("eua", list_variables) * sizeof(int));
char *brasil = malloc(searchVariable("brasil", list_variables) * sizeof(char));
float *paris = malloc(searchVariable("paris", list_variables) * sizeof(float));
//Alloc the void type (Undefined)
void *horse = malloc(searchVariable("horse", list_variables) * sizeof(void));
//---
//Set values
*eua = 5; //Integer
strcpy(brasil, "Cool!"); //String
*paris = 3.14; //Float
*(int*)horse = (int) 7; //Set a integer value to void pointer!
//---
//Show up!
printf("Variable eua: %d \n", *eua);
printf("Variable brasil: %s \n", brasil);
printf("Variable paris: %f \n", *paris);
printf("Variable horse: %d \n", *((int*)horse));
return EXIT_SUCCESS;
}
//Linked list functions...
//Allocate the linked list on memory
void createList() {
list_variables = malloc( sizeof (map));
list_variables->next = NULL;
}
//Insert the .MAP values into linked list
void insert(char name[], int size, map *p)
{
map *new;
new = malloc( sizeof (map));
new->size = size;
strcpy(new->name, name);
new->next = p->next;
p->next = new;
}
//Show variables loaded from .MAP file
void showList(map *list)
{
map *p;
for (p = list->next; p != NULL; p = p->next)
printf("Variable: %s, Size: %d \n", p->name, p->size);
}
//Search variable in memory and return the size respective
unsigned int searchVariable(char name[], map *list)
{
map *p;
p = list->next;
while (p != NULL && strcmp(name, p->name) != 0)
p = p->next;
return p->size;
}
//---
//Procedure to parse the map file in the specified structure!
void parseMapFile(char path[]) {
char line[80];
char name[40];
unsigned int size;
FILE *fp = fopen(path, "r");
while(fgets(line, 80, fp) != NULL)
{
sscanf (line, "%s %d", name, &size);
insert(name, size, list_variables);
}
fclose(fp);
}
With this you really can allocate dynamic space with values stored in a file.
I'm having trouble replacing a whole word in a sentence.
For example:
Replace:
the to a
hello to hi
house to tree
Input:
Hello there, this is the house.
Output:
Hi there, this is a tree.
Is it possible to do it only with the <string.h> library, with no Regex etc.?
May be this can help you
str-replace-c
It's entirely possible, but the standard library doesn't have any function to support it directly. Therefore, to do it, you'd typically use something like strstr to find the existing instance(s) of the string you want to replace, memmove to move the rest of the string, an overwrite the original with the desired replacement either manually, or perhaps with strncpy.
Note that in this case, your replacement strings are all shorter than the original they're replacing. This implies that the replacements can always be done safely. If the replacement is longer than the original, you'll also have to do something to track the maximum string length, and ensure you don't exceed it.
Oh, one other not-so-minor point, but if you're searching for something as a complete word, not just an occurrence of that string inside another word, you probably want to search for <space>word<space>, except at the beginning or end of the string, so (for example) you wouldn't replace the in there with a and turn the first word from there to are.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
typedef struct pair {
char *key;
char *value;
} Pair;
int cmp(const void *a, const void *b){
return strcmp(((const Pair*)a)->key, ((const Pair*)b)->key);
}
char *dictionary(const char *word){
static const Pair table[] =
{{"hello", "hi"}, {"house", "tree"},{"the", "a"}};
char *p, *wk = strdup(word);
Pair key, *pair;
for(p=wk;*p;++p)
*p = tolower(*p);
key.key = wk;
pair=bsearch(&key, table, sizeof(table)/sizeof(Pair), sizeof(Pair), cmp);
free(wk);
if(pair){
wk=strdup(pair->value);
if(isupper(*word))
*wk = toupper(*wk);//capitalize
return wk;
}
return NULL;
}
typedef char Type;
typedef struct vector {
size_t size;
size_t capacity;
Type *array;
} Vector;
Vector *vec_make(){
Vector *v;
v = (Vector*)malloc(sizeof(Vector));
if(v){
v->size = 0;
v->capacity=16;
v->array=(Type*)realloc(NULL, sizeof(Type)*(v->capacity += 16));
}
return v;
}
void vec_add(Vector *v, Type value){
v->array[v->size] = value;
if(++v->size == v->capacity){
v->array=(Type*)realloc(v->array, sizeof(Type)*(v->capacity += 16));
if(!v->array){
perror("memory not enough");
exit(-1);
}
}
}
void vec_adds(Vector *v, Type *values, size_t size){
while(size--)
vec_add(v, *values++);
}
char *convert(const char *str){
static const char *delimiters = " \t\n,.!?";
char *in = strdup(str);
char *out;
char *inp = in;
Vector *v = vec_make();
while(*inp){
size_t size;
if(size = strcspn(inp, delimiters)){
char *word, *cnv_word;
word = malloc(size+1);
memcpy(word, inp, size);
word[size]='\0';
if(NULL==(cnv_word = dictionary(word)))
vec_adds(v, word, size);
else
for(out = cnv_word; *out; ++out)
vec_add(v, *out);
free(word);
free(cnv_word);
inp += size;
}
if(size = strspn(inp, delimiters)){
vec_adds(v, inp, size);
inp += size;
}
}
vec_add(v, '\0');
out = v->array;
free(v);
free(in);
return out;
}
int main(void){
char input[] = "Hello there, this is the house.";
char *output = convert(input);
puts(input);
puts(output);
free(output);
return 0;
}
/* result
Hello there, this is the house.
Hi there, this is a tree.
*/
create a hash of before and after, ie what you are searching for and what you want to replace with, iterate through the string and search for the words with something like KMP or rabin karp and find what you need in your hash table.
int main() {
Employee *array[SIZE]; //Employee is a typedef struct --includes char *name, DATE *dateOfBirth, DATE is also a typedef struct, has 3 int fields month, day, year,`
fillArray(array, &count, fpin1, fpin2);
freeMemory(array, int count);
}
fillArray(Employee *array[], int *count, FILE *fpin1, FILE *fpin2)
char buffer[MAX], buffer2[MAX];
while (fgets(buffer, MAX, fpin1) != NULL && fgets(buffer2, MAX, fpin2) != NULL){
array[*count]->name = (char *) malloc(sizeof(char)*25);
assert(array[*count]->name != NULL);
strncpy(array[*count]->name, buffer, 15);
strncpy(buffer2, temp, 2);
array[*count]->dateOfBirth->day = atoi(temp)
}
The code compiles but keeps failing with segmentation fault, it seems to fail at my fgets? or my malloc, what am I doing wrong? I really can't seem to figure that out.
Also how would you go about freeing this memory in a
freeMemory(Employee *array[], int count)
function?
Should be:
int main() {
Employee array[SIZE]; //Employee is a typedef struct --includes char *name, DATE *dateOfBirth, DATE is also a typedef struct, has 3 int fields month, day, year,`
fillArray(&array, &count, fpin1, fpin2);
freeMemory(&array, int count);
}
You aren't allocating your Employee objects anywhere, so array[0] points to some random address.
Employee* array[SIZE];
This is an array that stores pointers to Employee structs.
I think you mean
fillArray(Employee* array[], int* count, FILE *fpin1, FILE *fpin2)
{
char buffer[MAX], buffer2[MAX];
int i = 0;
while ( fgets(buffer, MAX, fpin1) != NULL &&
fgets(buffer2, MAX, fpin2) != NULL )
{
// the array does not hold any valid memory address.
array[i] = malloc( sizeof(Employee) );
assert( array[i] != NULL );
// now on the new employee add some char memory
(array[i])->name = malloc( sizeof(char) * 25 );
assert(array[i]->name != NULL);
strncpy(array[i]->name, buffer, 15);
strncpy(buffer2, temp, 2);
array[i]->dateOfBirth->day = atoi(temp)
++i;
(*count)++;
}
}
doing array[*count] besides looking weird, always modifies the same index. You never modified *count anywhere.
This code does not check that you do not exceed the bounds of the array passed.
Also : for the freeMemory()
freeMemory(Employee* array[], int count)
{
int i = 0;
while( i < count )
{
free(array[i]);
array[i] = NULL;
++i;
}
}