C Using malloc on a char string - c

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.

Related

Freeing structure elements in C

I have a structure:
struct student{
int roll_no;
char *name = malloc(25 * sizeof(char));;
char *phone_no = malloc(10 * sizeof(char));;
char *dob = malloc(10 * sizeof(char));;
}*s1;
int main(){
s1 = malloc(5 * sizeof(student)); //array of student
//.....
}
What is appropriate code for the complete loop for allocating an array of student of size 'n' and then de-allocating it afterwards?
Note: The question here deals with allocation and de-allocation of elements of the instance of a structure.
This...
typedef struct student{
int roll_no; // (the following illegal syntax commented out)
char *name; // = malloc(25 * sizeof(char));;
char *phone_no; // = malloc(10 * sizeof(char));;
char *dob; // = malloc(10 * sizeof(char));;
}*s1;
...from what is being described as the need, (minus the illegal assignment statements) could probably better be formed as:
typedef struct {
int roll_no;
char *name; //needs memory
char *phone; //needs memory
char *dob; //needs memory
}STUDENT;
Then, use the new variable type: STUDENT, to create the instances of the struct as needed. Your OP indicates you need 5:
STUDENT s[5]; //Although this array needs no memory, the
//members referenced by it do
//(as indicated above)
Now, all that is necessary is to create memory for the 3 members that require it, in each of the 5 instances.
for(i=0;i<5;i++)
{
s[i].name = calloc(80, 1); //calloc creates AND initializes memory.
s[i].phone = calloc(20, 1); //therefore safer than malloc IMO.
s[i].dob = calloc(20, 1); //Also, change values as needed to support actual
//length needs for name, phone and dob
}
// Use the string members of s[i] as you would any other string, But do not
// forget to free them when no longer needed.
...
for(i=0;i<5;i++)
{
free(s[i].name);
free(s[i].phone);
free(s[i].dob);
}
Note, because of the way the array s is created in this example, i.e. with memory on the stack instead of the heap, there is no need to free it.
One other note, the example code above focused on a method to create memory for the char * members of your struct array, but when actually coding for keeps, the return of [m][c][re]alloc should always be checked that memory was created before trying to use the variable. For example:
s[i].name = calloc(80, 1);
if(!s[i].name) //checking that memory was created
{
;//if failed, then handle error.
}
...
In addition to ryyker's answer, if you want to do it dynamically:
#include <stdlib.h>
struct student{
int roll_no;
char *name;
char *phone;
char *dob;
};
int main()
{
int i, student_count = 5;
struct student ** s = malloc(sizeof(struct student *) * student_count);
if (s)
{
for (i = 0; i < student_count; ++i)
{
s[i] = malloc(sizeof(struct student));
if (s[i])
{
//set up student's members
}
}
for (i = 0; i < student_count; ++i)
{
//free student's members before the next line.
free(s[i]);
}
free(s);
}
return 0;
}
You must free everything you malloc, and as mentioned in the comments you cannot malloc inside the struct.
#include <stdio.h>
#include <stdlib.h>
#define NUM_STUDENTS 5
struct student{
int roll_no;
char *name;
char *phone;
char *dob;
};
int main(void)
{
int i;
// if this was me, I would simply replace this with
// struct student s[NUM_STUDENTS];, but the goal here is to illustrate
// malloc and free
struct student* s = malloc(sizeof(struct student) * NUM_STUDENTS);
if (s == NULL) // handle error
for (i=0; i<NUM_STUDENTS; i++)
{
// sizeof(char) is guaranteed to be 1, so it can be left out
s[i].name = malloc(25);
if (s[i].name == NULL) // handle error
s[i].phone = malloc(10);
if (s[i].phone == NULL) // handle error
s[i].dob = malloc(10);
if (s[i].dob == NULL) // handle error
}
// do stuff with with the data
....
// time to clean up, free in the reverse order from malloc
for (i=0; i<NUM_STUDENTS; i++)
{
// the dob, phone, name order here isn't important, just make sure you
// free each struct member before freeing the struct
free(s[i].dob);
free(s[i].phone);
free(s[i].name);
}
// now that all the members are freed, we can safely free s
free(s);
return 0;
}
User Abhijit gave an answser that was in the right direction, but not complete. His answer should have been:
typedef struct STUDENT{
int roll_no;
char *name;
char *phone;
char *dob;
}student;
void example(int n_students)
{
student **s;
int i;
s= malloc(n_students * sizeof(student *));
for (i=0; i<n_students; i++)
{
s[i]= malloc(sizeof(student));
s[i]->name= malloc(25);
s[i]->phone= malloc(10);
s[i]->dob= malloc(10);
}
// now free it:
for (i=0; i<n_students; i++)
{
free(s[i]->name);
free(s[i]->phone);
free(s[i]->dob);
free(s[i]);
}
free(s);
}

free() not freeing string from array of structs

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
// ...
}
}
}

Using an array of structures with call by reference

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));

Pointer is changing after function call, C

So I've written this program to represent a car park as a bitset, each space in the car park being one bit. I have a checkSpace function to check if a space is occupied or not and for some reason the pointer to my car park bitset changes or the data changes after I pass it into the function. To test it I set up the car park, I checked a space, then checked it again immediately after and for some reason the return value is changing when it shouldn't be. Any help would be appreciated!
struct carPark{
int spaces, levels;
unsigned char * park;
};
struct carPark * emptyCarPark(int levels, int spaces){
int chars = (spaces*levels)/8;
if((spaces*levels)%8 != 0){
chars++;
}
unsigned char park[chars];
for (int i = 0; i < chars; ++i){
park[i] = 0;
}
unsigned char * ptr = &park[0];
struct carPark * myPark = malloc(sizeof(struct carPark));
myPark->park = ptr;
myPark->spaces = spaces;
myPark->levels = levels;
return myPark;
}
int checkSpace(int level, int spaceNum, struct carPark * carpark){
int charPosition = ((level*carpark->spaces) + spaceNum)/8;
int bitPosition = ((level*carpark->spaces) + spaceNum)%8;
if(carpark->park[charPosition]&&(1<<bitPosition) != 0){
return 1;
}
return 0;
}
int main(int argc, char const *argv[]){
struct carPark * myPark = emptyCarPark(5,20);
printf("1st check: %d\n",checkSpace(1,1,myPark));
printf("Second check: %d\n",checkSpace(1,1,myPark));
return 0;
}
So when I run the program I get:
1st check: 0
Second check: 1
Look at the code below - in emptyCarPark() you are allocating the park array on the stack, and then returning a pointer to it. As soon as the function returns, the park array is no longer allocated and you have a dangling pointer - for more information, see: Cause of dangling pointers (Wikipedia)
unsigned char park[chars];
for (int i = 0; i < chars; ++i){
park[i] = 0;
}
// This is the pointer to an object on the stack.
unsigned char * ptr = &park[0];
struct carPark * myPark = malloc(sizeof(struct carPark));
myPark->park = ptr;

Allocating and Freeing pointer to pointer

I'm attempting to pass a pointer to a pointer (char**) into a function that will initialize it, and then pass it into another function that will free the memory, however I'm getting seg faults on the freeing which leads me to believe my allocation is going wrong.
Valgrind is reporting use of uninitalized value at this line. tmp[i] is pointing to 0x0.
if(tmp[i]) free((char*)tmp[i]);
Here is the code (this is only test code)
void
alloc_strings(char ***test, int count)
{
char **tmp = *test;
tmp = malloc(count * sizeof(char*));
int i;
for(i = 0; i < count; i++) {
tmp[i] = malloc(6);
strcpy(tmp[i],"Hello");
}
}
void
free_strings(char ***test, int count)
{
char **tmp = *test;
int i;
for(i = 0; i < count; i++) {
if(tmp[i]) free((char*)tmp[i]);
}
if(tmp)
free(tmp);
}
And the invocation:
int
main(int argc, char **argv)
{
char **test;
alloc_strings(&test, 10);
free_strings(&test, 10);
return 0;
}
I have been playing around with this for a while, reading up on pointers etc however can't get my head around the issue. Any thoughts greatly appreciated!
You need to assign to *test, not to assign from it. How about:
void
alloc_strings(char ***test, int count)
{
char **tmp = malloc(count * sizeof *tmp);
/*...*/
*test = tmp;
}
In the code example,
alloc_strings(char ***test, int count)
{
char **tmp = *test;
*test should have some space to store a pointer to char ** which currently is not allocated. Hence, if the example is as this
char** array[1];
alloc_strings(&array[0], 7);
I feel that the code will work.

Resources