This question already has answers here:
How can I correctly assign a new string value?
(4 answers)
Closed 3 months ago.
I am learning C and I have trouble correctly using free() on char *word from my struck. The code works in its currect form but crashes if I uncomment the line in the for loop ant the end of main. How do I free it correctly?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#include <errno.h>
typedef struct container
{
char *word;
int amount;
} wordContainer;
wordContainer *SetupWordList(int *size, int *lastInit, wordContainer *listIN, bool realloc);
int main(int argc, const char *argv[])
{
wordContainer *listWords = NULL;
int listSize = 10;
int listLastInit = 0;
listWords = SetupWordList(&listSize, &listLastInit, listWords, false);
for (int i = 0; i < listSize/2; i++)
{
fprintf(stdout, "Word: %s | Amount: %i\n", listWords[i].word, listWords[i].amount);
}
for (int i = 0; i < listSize/2; i++)
{
//free(listWords[i].word);
}
free(listWords);
exit(EXIT_SUCCESS);
}
wordContainer *SetupWordList(int *size, int *lastInit, wordContainer *listIN, bool reallocate)
{
if(!reallocate)
{
listIN = (wordContainer *)malloc((*size) * sizeof(wordContainer));
if (listIN == NULL)
{
fprintf(stderr, "Could not allocate enought memory.");
exit(EXIT_FAILURE);
}
}
else
{
listIN = (wordContainer *)realloc(listIN, (*size) * sizeof(wordContainer));
}
for (int i = (*lastInit); i < (*size); i++)
{
listIN[i].word = (char *)malloc(50*sizeof(char));
listIN[i].word = "empty";
listIN[i].word = "cow";
listIN[i].amount = 0;
}
*lastInit = *size;
*size *= 2;
return listIN;
}
I have honestly no idea what is the problem here, everything I could find online sugested that I am maybe using free() multiple times on the same location or that I have overwriten buffers but I don't see how this is the case here.
for (int i = (*lastInit); i < (*size); i++)
{
listIN[i].word = (char *)malloc(50*sizeof(char));
strcpy(listIN[i].word, "empty");
}
Solved my problem. Did not realise that "listIN[i].word = "empty";" makes me lose my mallocated pointer.
Related
I am trying to pass the pointer to a struct to a function to create an array of the struct there. The overall idea is:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct items
{
int number;
char *name;
char *description;
} ITEMS;
int process(ITEMS **items)
{
int i = 0, something = 200;
// for loop is for the representation.
// The actual data come from MySQL row loop
for (int j = 100; j < something; j++)
{
// Growing the array of struct
items = realloc(items, (i + 1) * sizeof(*items));
// Adding items here
items[i]->number = j;
strcpy(items[i]->name, "Some name"); // it comes from a variable
strcpy(items[i]->description, "Some text");
i++;
}
return i;
}
int main()
{
ITEMS *items;
int num_items = process(&items);
for (int i = 0; i < num_items; i++)
{
printf("%d - %s - %s\n", items[i].number, items[i].name,
items[i].description);
}
return 0;
}
but I am struggling with reallocating the memory for the struct (and with the pointers too).
The pointer to pointer must be de-referenced in the function so the allocation is visible in the calling function.
strdup is use to allocate memory to the pointers in the structure.
It is better to use a temporary variable for the reallocation.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct items
{
int number;
char *name;
char *description;
} ITEMS;
int process(ITEMS **items)
{
int i = 0;
// Growing the array of struct
*items = realloc(*items, (i + 1) * sizeof(**items));
// repeating this step in a loop of adding items
// Adding items here
(*items)[i].number = 72;
(*items)[i].name = strdup( "Some name"); // it comes from a variable
(*items)[i].description = strdup ("Some text");
i++;
*items = realloc(*items, (i + 1) * sizeof(**items));
// another item
(*items)[i].number = 88;
(*items)[i].name = strdup( "Some name"); // it comes from a variable
(*items)[i].description = strdup ("Some text");
i++;
return i;
}
int main()
{
ITEMS *items = NULL;
int num_items = process(&items);
for (int i = 0; i < num_items; i++)
{
printf("%d - %s - %s\n", items[i].number, items[i].name, items[i].description);
}
return 0;
}
With better error detection
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct items
{
int number;
char *name;
char *description;
} ITEMS;
int process(ITEMS **items)
{
ITEMS *temp = NULL;
int i = 0;
// Growing the array of struct
if ( NULL == ( temp = realloc(*items, (i + 1) * sizeof(**items)))) {
fprintf ( stderr, "realloc problem\n");
return i;
}
*items = temp;
// repeating this step in a loop of adding items
// Adding items here
(*items)[i].number = 72;
(*items)[i].name = strdup( "Some name"); // it comes from a variable
(*items)[i].description = strdup ("Some text");
i++;
if ( NULL == ( temp = realloc(*items, (i + 1) * sizeof(**items)))) {
fprintf ( stderr, "realloc problem\n");
return i;
}
*items = temp;
// another item
(*items)[i].number = 88;
(*items)[i].name = strdup( "Some name"); // it comes from a variable
(*items)[i].description = strdup ("Some text");
i++;
return i;
}
int main()
{
ITEMS *items = NULL;
int num_items = process(&items);
for (int i = 0; i < num_items; i++)
{
printf("%d - %s - %s\n", items[i].number, items[i].name, items[i].description);
}
return 0;
}
I have problems with my code. It's a multithreading program that executes the following Linux command "# cat | sort | uniq -c | sort -nr". When I try to run the program in a virtual machine, I get a segmentation error, no core dumped. I have tried everything to fix this, but I still get the error. I see that the problem is in the main function and I don't know what it is. Could be either in pthread_join or maybe could be the max number of threads, declared globally. Can someone help me out? This is my code.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#define MAX_THREADS 0x40
#define MAX_STRING 124ULL
struct string_count_entry {
char* string;
int count;
};
struct string_count {
int nb_string;
struct string_count_entry* entries;
};
struct string_count* string_count_init() {
struct string_count* sc;
sc = malloc(sizeof(sc));
sc->entries = NULL;
sc->nb_string = 0;
return sc;
}
int addstring(struct string_count* pt, char* s) {
int i;
for (i = 0; i < pt->nb_string; i++) {
if (strcmp(pt->entries[i].string, s))
break;
}
if (i == pt->nb_string) {
pt->entries = realloc(pt->entries,
pt->nb_string + 1 * sizeof(pt->entries[0]));
if (pt->entries == NULL)
return -1;
pt->nb_string++;
pt->entries[i].string = s;
}
pt->entries[i].count++;
return 0;
}
static inline int Compare(const void* pt1, const void* pt2) {
struct string_count_entry* a = malloc(sizeof(pt2));
struct string_count_entry* b = malloc(sizeof(pt1));
if (a->count == b->count)
return strcmp(a->string, b->string);
return a->count - b->count;
}
void string_count_pint(struct string_count* sc) {
int i;
qsort(sc->entries, sc->nb_string, sizeof(struct string_count), Compare);
i = 0;
while (i < sc->nb_string) {
printf("%d %s\n", sc->entries[i].count, sc->entries[i].string);
i++;
}
}
void string_count_free(void* pt) {
struct string_count* sc = malloc(sizeof(pt));
char i;
for (i = 0; i < sc->nb_string; i++) {
free(sc->entries[i].string);
}
free(sc->entries);
}
char* readline(void) {
int i = 0;
char c;
char* linebuf = (char*)malloc(MAX_STRING);
while (read(0, &c, 1) != 0) {
if (c == '\n') {
linebuf[i] = '\0';
return linebuf;
}
linebuf[i++] = c;
}
return NULL;
}
void* thread_main(void* arg) {
struct string_count* sc = malloc(sizeof(arg));
char* line;
while ((line == readline()) != '\0') {
addstring(sc, line);
}
return NULL;
}
int main(int argc, char** argv) {
int nbthreads;
int i;
pthread_t threads[MAX_THREADS];
struct string_count* sc;
if (argc != 1) {
fprintf(stderr, "usage: %s <nb threads>\n", argv[0]);
return EXIT_FAILURE;
}
nbthreads = atoi(argv[1]);
sc = malloc(sizeof(nbthreads));
for (i = 0; i < nbthreads; i++) {
pthread_create(&threads[i], NULL, thread_main, sc);
}
do {
pthread_join(threads[nbthreads--], NULL);
} while (nbthreads > 0);
string_count_free(sc);
string_count_pint(sc);
return EXIT_SUCCESS;
}
I suspect the bug is in this line: sc = malloc(sizeof(nbthreads));
You probably wanted sc = malloc(sizeof(string_count));
I'm also not sure if struct string_count* sc = malloc(sizeof(arg)); does what you intended in thread_main.
You probably need the sc in main be an array and pass a different item in it to each thread and then aggregate them after the join.
Here are the first few errors I have spotted, in no particular order.
Unprotected modification of data structures from multiple threads. Read something about multithreading. Pay attention to the word "mutex".
pthread_join(threads[nbthreads--], NULL); goes out of bounds.
struct string_count* sc = malloc(sizeof(arg)); makes no sense. sizeof(arg) is the size of a pointer (8 on most PC-like systems). This is not enough to hold one struct string_count.
struct string_count_entry* a = malloc(sizeof(pt2)); apparently has even less sense. You are allocating something in a string comparison function, using a wrong size, then you are using the allocated memory without initializing it, and without even trying to compare the things passed to the function.
while ((line == readline()) != '\0') does not assign anything.
pt->entries = realloc(pt->entries, pt->nb_string + 1 * sizeof(pt->entries[0])); is missing a couple of parentheses.
This function is a part of program which will gain statistics about books (amount of specific letters, words etc.). Thing is that segmentation fault appears when trying to malloc:
*wordArray[arrayIndex] = malloc(sizeof(***wordArray)*(wcslen(newWord)+1));
after reallocing whole array
*wordArray = realloc(*wordArray, (arrayIndex+1)*sizeof(**wordArray));
I know that realloc isn't really efficent but the most important thing at the moment is to understand why it doesn't work at all. Thanks a lot.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
#include <wctype.h>
#include <wchar.h>
#define X 2
void wordManager(wchar_t ***, int **, wchar_t *);
int main(int argc, char **argv){
setlocale(LC_ALL, "");
wchar_t **wordArray;
int *wordAmount;
wchar_t word[50];
for(int i=0; i<X; i++){
scanf("%ls", word);
wordManager(&wordArray, &wordAmount, word);
}
for(int i=0; i<X; i++){
printf("%ls; %d times\n", wordArray[i], wordAmount[i]);
}
}
void wordManager(wchar_t ***wordArray, int **wordAmount, wchar_t *newWord){
static int isArrayInitialised = 0;
static int isArrayEmpty = 1;
static int arrayIndex = 0;
int wordLocation;
if(!isArrayInitialised){
*wordArray = malloc(sizeof(**wordArray)*1);
if(*wordArray==NULL){
printf("Error mallocing wordArray");
exit(EXIT_FAILURE);
}
*wordAmount = calloc(1, sizeof(*wordAmount));
if(*wordAmount==NULL){
printf("Error callocing wordAmount");
exit(EXIT_FAILURE);
}
isArrayInitialised = 1;
}
if(isArrayEmpty){
*wordArray[0] = malloc(sizeof(***wordArray)*(wcslen(newWord)+1));
wcscpy(*wordArray[0], newWord);
*wordAmount[0] = 1;
isArrayEmpty = 0;
}
else{
//Check if word is already in an array.
wordLocation = 0;
for(; wordLocation<arrayIndex+1; wordLocation++){
if(!wcscmp(*wordArray[wordLocation], newWord)) break;
}
printf("%d\n", wordLocation);
//Word hasn't been found. Then:
if(wordLocation==arrayIndex+1){
arrayIndex++; //Increase arrays' volume.
*wordArray = realloc(*wordArray, (arrayIndex+1)*sizeof(**wordArray));
if(*wordArray==NULL){
printf("Error reallocating wordArray memory.\n Array index: %d", arrayIndex);
exit(EXIT_FAILURE);
}
*wordAmount = realloc(*wordAmount, (arrayIndex+1)*sizeof(**wordAmount));
if(*wordAmount==NULL){
printf("Error reallocating wordAmount memory.\n Array index: %d", arrayIndex);
exit(EXIT_FAILURE);
}
*wordArray[arrayIndex] = malloc(sizeof(***wordArray)*(wcslen(newWord)+1));
wcscpy(*wordArray[arrayIndex], newWord);
*wordAmount[arrayIndex] = 1;
}
//Word has been found in an array.
else{
(*wordAmount[wordLocation])++;
}
}
}
I am having an error with the code we are using, was wondering if someone could help debug. Seems like we are getting a malloc error. Thanks.
void readWords(char norm_word[MAXSIZE], Word ** array) {
int i = 0;
bool found = false;
int result = 0;
Word * current_pointer = malloc (sizeof(Word*));//creates a temporary variable for each pointer in the array
for (i=0; i<word_counter; i++) {
current_pointer = *(array+i); //accesses the current pointer
result = strcmp(norm_word, (current_pointer -> word)); //compares the string to each stored string
if (result == 0) {
found = true;
(current_pointer->freq)++;
break;
}
}
if(!found) {
if(pointer_counter == word_counter) {
array = realloc(array, sizeof(array)*2);
pointer_counter*=2;
}
Word * new_pointer = (Word*) malloc (sizeof(Word*));
strcpy(new_pointer -> word, norm_word);
*(array + (pointer_counter - 1)) = new_pointer;
word_counter++;
}
;
}
All pointers have the same size on your system. So a sizeof always returns the same size for any pointer. You want to allocate for the structure, so you need to use sizeof on the name without the star. malloc will return the pointer to that block of memory afterwards.
Here is a short implementation:
#include <iostream>
#include <string>
typedef struct
{
int num;
int numnum;
}numbers;
int main(int argc, char ** argv)
{
numbers* n = (numbers*)malloc(sizeof(numbers));
n->num = 1;
n->numnum = 2;
free(n);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define MAXSIZE 64
typedef struct word {
char word[MAXSIZE];
int freq;
} Word;
int word_counter = 0;
size_t pointer_counter = 16;//Number of pointers that ensure
void readWords(char norm_word[MAXSIZE], Word ** array) {
int i = 0;
bool found = false;
Word *current_pointer = *array;
for (i=0; i<word_counter; i++) {
if(strcmp(norm_word, current_pointer->word) == 0){
found = true;
current_pointer->freq++;
break;
}
++current_pointer;
}
if(!found) {
if(pointer_counter == word_counter) {
pointer_counter *= 2;
*array = realloc(*array, sizeof(Word)*pointer_counter);
}
Word *new_pointer = *array + word_counter;
new_pointer->freq = 1;
strcpy(new_pointer->word, norm_word);
++word_counter;
}
}
int main(void){
Word *vocabulary = calloc(pointer_counter, sizeof(Word));
char norm_word[MAXSIZE];
while(1==scanf("%s", norm_word)){
readWords(norm_word, &vocabulary);
}
{
int i;
for(i = 0; i < word_counter; ++i){
printf("%s(%d)\n", vocabulary[i].word, vocabulary[i].freq);
}
}
free(vocabulary);
return 0;
}
I don't think I properly understand how to allocate memory for what I want to do.
I would like my program to store arguments from the command line into an array of stucts called Command which has char **args in it. for example if I run
./test.c echo hello : ls -l
I want it to store it as this
commands[0].args[0]= echo
commands[0].args[1]= hello
commands[1].args[0]= ls
commands[1].args[1]= -l
But instead my code is storing it in this way
commands[0].args[0]= echo
commands[0].args[1]= hello
commands[0].args[2]= ls
commands[0].args[3]= -l
commands[1].args[0]= ls
commands[1].args[1]= -l
Could someone help me understand why it is storing ls -l in 2 places? Here is my code:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
typedef struct test {
char **args;
} Command;
int main(int argc, char *argv[])
{
int i, j, k;
Command *commands;
j = k = 0;
commands = (Command *)malloc(argc * sizeof(Command));
for (i = 1; i < argc; i++)
{
if (strcmp(argv[i], ":") == 0)
{
j++;
k = 0;
}
else {
commands[j].args = (char **)realloc(commands[j].args, (k+1) * sizeof(char*));
commands[j].args[k++] = argv[i];
}
}
for (i = 0; i <= j; i++)
{
for (k = 0; k < 5; k++)
{
printf("commands[%d].args[%d]= %s\n", i, k, commands[i].args[k]);
}
}
return EXIT_SUCCESS;
}
Your data storage structure has no way of telling how many strings in commands[j] are valid. So I think it's putting two pointers each in commands[0] and commands[1] just like you expect. But then your print loop looks at commands[0].args[k] for k all the way up to 4, even though it's only valid to look at the first two. When you get up to looking at commands[0].args[2], the result is undefined. (Showing memory from somewhere else in your program, crashing, and catching fire are just a few of the things a program is allowed to do if you use undefined behavior.)
To figure out how many arguments are in each command, you could add a counter member to your struct test. Or maybe allocate one more pointer than there are arguments, and put a NULL after the last argument.
Here is how I would allocate the memory:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct cmd_s {
int num;
char **args;
} cmd_t;
void print_cmds(cmd_t *c, int num) {
int i, j;
for (i=0;i<=num;i++) {
for (j=0;j<c[i].num;j++)
printf("cmds[%d][%d] = %s\n", i, j,c[i].args[j]);
}
}
int main(int argc, char *argv[]) {
int i, j = 0, k = 0;
cmd_t *cmds;
cmds = (cmd_t *)malloc(sizeof(cmd_t));
cmds[0].args = NULL;
cmds[0].num = 0;
for (i=1;i<argc;i++) {
if (strcmp(argv[i], ":") == 0) {
cmds = (cmd_t *)realloc(cmds, (sizeof(cmd_t) * ++j) + 1);
cmds[j].args = NULL;
cmds[j].num = 0;
continue;
}
cmds[j].args = (char **)realloc(cmds[j].args, sizeof(char *) * ++cmds[j].num);
cmds[j].args[cmds[j].num-1] = (char *)malloc(50);
strcpy(cmds[j].args[cmds[j].num-1], argv[i]);
}
print_cmds(cmds, j);
for (i=0;i<=j;i++) {
for(k=0;k<cmds[i].num;k++)
free(cmds[i].args[k]);
free(cmds[i].args);
}
free(cmds);
return 0;
}
Each of your Command structs only have one arg
Perhaps you should consider
typedef struct test {
char **args[5];
} Command;
and then design a better data structure, like a list of lists.
Perhaps you should store the length of args in the struct?
typedef struct test {
char ** args;
unsigned length;
} Command;
Also, maybe you should consider using some of the built in functionality of the C string library. For example, strtok splits a string using the delimiters you give it.