Detect the head node of linked list - c

typedef struct s_tok
{
int len;
char *tok;
int type;
struct s_tok *next;
} t_tok;
static int wordlen(char *wordstart, int pos);
static char *word(char *cmdline, int len, int s_pos);
static void add_word(char *cmdline, int *pos, t_tok **token);
t_tok *tokenization(char *cmdline)
{
t_tok *tokens;
t_tok *tmp;
int i;
i = -1;
tokens = malloc(sizeof(t_tok));
if(!tokens)
return (NULL);
tokens->tok = ".";
tokens->next = NULL;
tmp = tokens;
while(cmdline[++i])
{
if(cmdline[i] && ft_iswordpart(cmdline[i]))
add_word(cmdline, &i, &tokens);
}
return (tmp);
}
static void add_word(char *cmdline, int *pos, t_tok **token)
{
char *wordpart;
int len;
len = wordlen(cmdline, *pos);
wordpart = word(cmdline, len, *pos);
while((*token)->next != NULL)
(*token) = (*token)->next;
(*token)->next = new_token(len, wordpart, WORD);
free(wordpart);
*pos += len;
}
static int wordlen(char *wordstart, int s_pos)
{
int i;
i = 0;
while(wordstart[s_pos] && ft_iswordpart(wordstart[s_pos]))
{
s_pos++;
i++;
}
return (i);
}
static char *word(char *cmdline, int len, int s_pos)
{
char *word;
int i;
i = 0;
word = malloc(sizeof(char) * (len + 1));
while(i < len)
{
word[i] = cmdline[s_pos];
s_pos++;
i++;
}
word[i] = '\0';
return (word);
}
I have a tokenization function which should return me a tokens detected on command prompt. My t_tok struct which you can see above can store length of my token token as (char*) and type of the token. if i launch this while loop I must the top of while loop make a first node because if the head or first node of my tokens struct doesn't exist it shows me segmentation fault. Can you ask me how can I implement the adding node without creating first node by hand.

You do it by treating an initially null pointer as an list-of-none.
First, change tokenization as follows:
t_tok *tokenization(char *cmdline)
{
t_tok *tokens = NULL; // << Note: initially NULL
int i = -1;
while (cmdline[++i])
{
if (cmdline[i] && ft_iswordpart(cmdline[i]))
add_word(cmdline, &i, &tokens); // <== pass by address-of-pointer here
}
return tokens;
}
Then, the add-word function accomodates by looking for a null pointer on which to stash the new node. There are better ways to do this, but you seem to be shooting for the simple scan-to-end approach, which would look liks this:
static void add_word(char *cmdline, int *pos, t_tok **token)
{
int len = wordlen(cmdline, *pos);
char *wordpart = word(cmdline, len, *pos);
// note: this stops immediately if `*token`
// already points to a null pointer
while (*token)
token = &(*token)->next;
*token = new_token(len, wordpart, WORD);
free(wordpart);
*pos += len;
}
That's it. Assuming new_token (which you didn't show) properly allocates a new record and sets all members, including the next member as NULL, this should do what you want.

Related

C Using malloc on a char string

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.

Need help i get segmentation fault in program in C

First I will explain what I want to program. I want to open a directory and get all the files names and their number (in the directory). I want to allocate certain amount of memory for the number of files I have found, and a certain amount of memory for their names. I will give an example.
Lets say we have got a directory named dir and that directory has 4 files in it. The 4 files are named as follows: lalo, camo, mara, sarw.
I want my program to work as follows
Go into dir and while finding files keep allocating memory in order to store them (like a table of strings where I don't know the exact size because I don't know how many files I will find). I am storing the filenames character by character and I keep allocating memory as needed, every time I read one char I am realocating memory and incrementing by 1. Same logic I follow to the files number where I keep incrementing the number of files and reallocating memory as needed. A table like this (pointers) is what I imagine filenames[numberOfFiles][stringCharacter].
I get a segmentation fault in function GetFiles(...) on the second loop here : *(*(entries+*number)+size) = dp->d_name[size];
int main()
{
int number,i;
char *mainDirectory = NULL,**names = NULL;
printf("Give the movies directory: ");
mainDirectory = ReadMainDirectory();
if(GetFiles(mainDirectory,&names,&number) != 0)
{
system("PAUSE");
return 1;
}
system("PAUSE");
return 0;
}
char* ReadMainDirectory()
{
char *dir,c;
int size = 1;
dir = (char*)malloc(size+1);
dir[size-1] = '\0';
while((c = getchar()) != '\n')
{
dir[size-1] = c;
size++;
dir = (char*)realloc(dir,size+1);
dir[size-1] = '\0';
}
return dir;
}
int GetFiles(char *dir,char ***names,int *number)
{
struct dirent *dp;
DIR *fd;
int size;
char **entries = NULL;
if ((fd = opendir(dir)) == NULL)
{
printf("Can't open directory %s!\n",dir);
return 0;
}
*number = 0;
size = 0;
entries = (char**)malloc((*number+1) * sizeof(char*));
*entries = (char*)malloc((size+1) * sizeof(char));
while ((dp = readdir(fd)) != NULL)
{
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
{
continue;
}
size = 0;
while(dp->d_name[size] != '\0')
{
*(*(entries+*number)+size) = dp->d_name[size];
size++;
*(entries+*number) = (char*)realloc(entries[*number],(size+1) * sizeof(char));
}
entries[*number][size] = '\0';
printf("%s\n",entries[*number]);
(*number)++;
entries = (char**)realloc(entries,(*number+1) * sizeof(char*));
}
*names = entries;
closedir(fd);
return 1;
}
int GetStringSize(char *string)
{
int size = 0;
while(string[size] != '\0')
{
size++;
}
return size;
}
int StringEndsWith(char* string,char* extension)
{
return !strcmp(string + strlen(string) - strlen(extension), extension);
}
A proper implementation of getfiles (gets all the files in a directory in a dynamic array) and provides a deallocator:
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
/* returns a NULL terminated array of files in directory */
char **getfilelist(const char *dirname) {
DIR *dp;
char **entries = NULL;
struct dirent *entry;
off_t index = 0;
dp = opendir(dirname);
if (!dp) {
perror(dirname);
return NULL;
}
while((entry = readdir(dp)) != NULL) {
/* increase entries array size by one pointer-size */
entries = realloc(entries, (1+index)*sizeof(char *));
/* strdup returns a newly allocated duplicate of a string that
* you must free yourself
*/
entries[index] = strdup(entry->d_name);
index++;
}
/* need one more entry for NULL termination */
entries = realloc(entries, (1+index)*sizeof(char *));
entries[index] = NULL;
return entries;
}
void putfilelist(char **entries) {
char **p;
if(!entries)
return;
for(p = entries; *p !=NULL ; p++) {
free(*p); /* free all the strdups */
}
free(entries); /* free the array of pointers */
}
An example of how you could use it:
int main(int argc, char **argv) {
char **p, **entries;
char *dir = (argc == 1 ? "." : argv[1]);
entries = getfilelist(dir);
for (p = entries; p && *p; p++) {
printf("%s\n", *p);
}
putfilelist(entries);
}
Updated solution,
In order to implement your solution without using any of the library code, and keep it to system calls, here is an example that implements everything that the above example does, without relying on higher-level library calls.
Note
The bottom functions are the same as the above example.
/*
* A partially low-level implementation using a direct system calls
* and internal memory management
*
* This is an opinionated (linux only) implementation of OP
*
* linux headers are only included for some of the constants and
* where it would be trivial to re-implement system calls (e.g. open, write etc.)
* which I am too lazy to do in this example.
*
*/
#define NDEBUG
#include <stdarg.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/fcntl.h>
#include <linux/unistd.h>
/* replace this macro with your own error handling messages */
#define handle_error(msg) \
do { my_fdputs(2, msg); my_exit(-127); } while (0)
#if !defined(NDEBUG)
#define assert(x) do { int __rv = (x); if(!__rv) { my_fdprintf(2, "assertion failed %s\n", #x); my_exit(__rv); } } while(0)
#else
#define assert(x) do {} while(0)
#endif
/* returns a NULL terminated array of files in directory */
/* low-level list builder using getdents */
void my_exit(int x)
{
syscall(SYS_exit_group, x);
}
/* a trivial malloc / realloc / free */
/* simple linked list memory accounting */
struct memblock {
struct memblock *next;
size_t size;
int free; /* flag */
int magic; /* canary value for debugging */
};
#define METASIZE sizeof(struct memblock)
void *global_base = NULL;
struct memblock *find_free_block(struct memblock **last, size_t size)
{
struct memblock *current = global_base;
while(current && !(current->free && current->size >= size)) {
*last = current;
current = current->next;
}
return current;
}
/*
* instead of using sbrk, we should really use mmap on newer
* linux kernels and do better accounting, however this is a
* simple example to get you started
*/
struct memblock *request_space(struct memblock *last, size_t size)
{
struct memblock *block;
void *request;
block = sbrk(0); /* get current program break */
request = sbrk(size + METASIZE);
assert((void *)block == request);
if(request == (void *)-1) {
return NULL;
}
if(last) {
last->next = block;
}
block->size = size;
block->next = NULL;
block->free = 0;
block->magic = 0x12345678;
return block;
}
struct memblock *get_memblock_ptr(void *ptr)
{
return (struct memblock *)ptr - 1;
}
/* a simple memcpy, can be optimized by taking alignment into account */
void *my_memcpy(void *dst, void *src, size_t len)
{
size_t i;
char *d = dst;
const char *s = src;
struct memblock *bd, *bs;
bd = get_memblock_ptr(dst);
for(i = 0; i < len; i++) {
d[i] = s[i];
}
return dst;
}
/* now to implement malloc */
void *my_malloc(size_t size)
{
struct memblock *block;
if(size == 0)
return NULL;
if(!global_base) {
block = request_space(NULL, size);
if(!block)
return NULL;
global_base = block;
}
else {
struct memblock *last = global_base;
block = find_free_block(&last, size);
if(!block) {
block = request_space(last, size);
if(!block) {
return NULL;
}
}
else {
block->free = 0;
block->magic = 0x77777777;
}
}
return (block+1);
}
void my_free(void *ptr)
{
struct memblock *block;
if (!ptr)
return;
block = get_memblock_ptr(ptr);
assert(block->free == 0);
assert(block->magic == 0x77777777 || block->magic == 0x12345678);
block->free = 1;
block->magic = 0x55555555;
}
void *my_realloc(void *ptr, size_t size)
{
struct memblock *block;
void *newptr;
if(!ptr)
return my_malloc(size);
block = get_memblock_ptr(ptr);
if(block->size >= size)
return ptr;
newptr = my_malloc(size);
if(!newptr) {
return NULL;
}
my_memcpy(newptr, ptr, block->size);
my_free(ptr);
return newptr;
}
/* trivial string functions */
size_t my_strlen(const char *src) {
size_t len = 0;
while(src[len])
len++;
return len;
}
char *my_strdup(const char *src)
{
char *dst;
char *p;
size_t len = 0, i;
len = my_strlen(src);
dst = my_malloc(1+len);
if(!dst)
return NULL;
for(i = 0; i < len; i++) {
dst[i] = src[i];
}
dst[i] = 0;
return dst;
}
/* trivial output functions */
my_fdputs(int fd, const char *str)
{
return write(fd, str, my_strlen(str));
}
int my_fdputc(int fd, char c)
{
return write(fd, &c, sizeof(char));
}
/* a very limited implementation of printf */
int my_fdvprintf(int fd, const char *fmt, va_list ap)
{
const char *p;
int count = 0;
for(p = fmt; p && *p; p++ ) {
if(*p == '%') {
p++;
switch(*p) {
case 's':
count += my_fdputs(fd, va_arg(ap, char *));
break;
case '%':
count += my_fdputc(fd, '%');
break;
default:
#ifndef NDEBUG
my_fdputs(2, "warning: unimplemented printf format specifier %");
my_fdputc(2, *p);
my_fdputc(2, '\n');
#endif
break;
}
}
else {
my_fdputc(fd, *p);
}
}
return count;
}
int my_fdprintf(int fd, const char *fmt, ...)
{
int rv;
va_list ap;
va_start(ap, fmt);
rv = my_fdvprintf(fd, fmt, ap);
va_end(ap);
return rv;
}
/* wrapper to linux getdents directory entry call */
/* linux dirent structure */
struct linux_dirent {
long d_ino;
off_t d_off;
unsigned short d_reclen;
char d_name[];
};
/* system call wrapper */
int getdents(int fd, void *buf, size_t bufsize)
{
return syscall(SYS_getdents, fd, buf, bufsize);
}
/* reimplement getfilelist using our getdents */
#define BUF_SIZE 1024
char **getfilelist(const char *dirname) {
int fd, nread;
char **entries = NULL;
off_t index = 0;
char buf[BUF_SIZE];
struct linux_dirent *d;
int bpos;
/* O_DIRECTORY since kernel 2.1 */
fd = open(dirname, O_DIRECTORY|O_RDONLY);
if (fd < 0) {
handle_error(dirname);
}
for(;;) {
nread = getdents(fd, buf, BUF_SIZE);
if (nread == -1)
handle_error("getdents");
if (nread == 0)
break;
for (bpos = 0; bpos < nread;) {
d = (struct linux_dirent *) (buf + bpos);
entries = my_realloc(entries, (1+index) * sizeof(char *));
entries[index++] = my_strdup(d->d_name);
bpos += d->d_reclen;
}
}
/* need one more entry for NULL termination */
entries = my_realloc(entries, (1+index)*sizeof(char *));
entries[index] = NULL;
close(fd);
return entries;
}
void putfilelist(char **entries) {
char **p;
if(!entries)
return;
for(p = entries; *p !=NULL ; p++) {
my_free(*p); /* free all the strdups */
}
my_free(entries); /* free the array of pointers */
}
int main(int argc, char **argv) {
char **p, **entries;
char *dir = (argc == 1 ? "." : argv[1]);
entries = getfilelist(dir);
for (p = entries; p && *p; p++) {
my_fdprintf(1, "%s\n", *p);
}
putfilelist(entries);
}
Hope you enjoy

How can I find symmetric difference in the words in two strings in C?

For example I have two strings:
lihuayu zhangxuehui sunyunlei guolei fuwenxia
lihuayu lixin fuwenxia zhangxuehui
And I will get
sunyunlei guolei lixin
I wrote following code
#include<stdio.h>
#include<string.h>
#define STRINGSIZE 64
void main()
{
char *line1 = NULL;
char *line2 = NULL;
size_t size1;
size_t size2;
getline(&line1, &size1, stdin);
getline(&line2, &size2, stdin);
char* spilted1 = strtok(line1, " ");
while (spilted1 != NULL){
if (strstr(line2, spilted1) == NULL){
printf("%s", spilted1);
}
spilted1 = strtok(NULL, " ");
}
}
But it's obviously wrong in that I can't get those distinct words in string2.
I know how to do it in Python but have no idea how to do it in C.
Here's one way:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { MAX_WORDS = 64 };
static int split_words(char *buffer, char **words, int max_words)
{
char *token;
char *next = buffer;
int num_words = 0;
while ((token = strtok(next, " \n")) != 0 && num_words < max_words)
{
words[num_words++] = token;
next = NULL;
}
return num_words;
}
static int word_in_list(char *word, char **list, int list_size)
{
for (int i = 0; i < list_size; i++)
{
if (strcmp(word, list[i]) == 0)
return 1;
}
return 0;
}
/* Print words in list w1 that do not appear in list w2 */
static void print_unique(char **w1, int n1, char **w2, int n2)
{
for (int i = 0; i < n1; i++)
{
if (!word_in_list(w1[i], w2, n2))
printf("[%s]\n", w1[i]);
}
}
int main(void)
{
char *line1 = NULL;
char *line2 = NULL;
size_t size1 = 0;
size_t size2 = 0;
if (getline(&line1, &size1, stdin) > 0 &&
getline(&line2, &size2, stdin) > 0)
{
char *w1[MAX_WORDS];
char *w2[MAX_WORDS];
int n1 = split_words(line1, w1, MAX_WORDS);
int n2 = split_words(line2, w2, MAX_WORDS);
print_unique(w1, n1, w2, n2);
print_unique(w2, n2, w1, n1);
}
free(line1);
free(line2);
return 0;
}
/*
You'll need two
arrays of char pointers, one for each line of input. You'll split the
first line into the first array, and the second line into the second
array. Then you'll go through the two arrays of pointers, comparing
strings and counting only those that do not match any of the entries in
the other array. (What do you do if one input line itself contains
repeats — The Lion, the Witch, and the Wardrobe for example? Also, do
you need to treat The as the same as the in that example?)
You can use strtok_r() or strtok_s() if you have them available; at a
pinch, you could use strtok(), but it is dangerous to use that in
library code. And you'll need to use strcmp() to compare the strings
— plus macros/functions from <ctype.h> to handle case-conversion if
that's appropriate.
Also note that strtok() is destructive. If you've split string 1 with
it, you can't then search in string 1 when you split string 2. Also
note that strstr("then came a deluge", "the") matches, even though most
people would not regard the haystack string as containing the needle
word the.
*/
The algorithm used is quadratic in the number of words (it runs in O(N2) time); it compares each unique word in one list with every word in the other list. You can do things like sort the lists and eliminate duplicates (in O(N.log N) time), and then step through the two lists to find unique words in linear time. Being quadratic won't matter for tens of words, and probably not for hundreds of words, but would probably begin to matter after that.
Compilation:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
> -Wold-style-definition -Werror uniq_words.c -o uniq_words
$
Example run:
$ cat data
lihuayu zhangxuehui sunyunlei guolei fuwenxia
lihuayu lixin fuwenxia zhangxuehui
$ uniq_words < data
[sunyunlei]
[guolei]
[lixin]
$
The square brackets around the data reassure me that the strings contain what I think they should contain.
Like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **split(const char *str, const char *delimiter, size_t *len);
int cmp(const void *a, const void *b);
void find_diff(char **a1, char **a2);
void drop(char **a);
int main(void){
char *line1 = NULL, *line2 = NULL;
size_t size1 = 0, size2 = 0;
getline(&line1, &size1, stdin);
getline(&line2, &size2, stdin);
//(1)split
size_t len1, len2;
char **array1 = split(line1, " \t\n", &len1);
char **array2 = split(line2, " \t\n", &len2);
//(2)sort
qsort(array1, len1, sizeof(*array1), cmp);
qsort(array2, len2, sizeof(*array2), cmp);
//(3)compare
find_diff(array1, array2);
drop(array1);drop(array2);
free(line1);free(line2);
return 0;
}
char **split(const char *str, const char *delimiter, size_t *len){
char *text, *p, *first, **array, **ret;
size_t c;
*len = 0;
text = strdup(str);//make clone
if(text == NULL) return NULL;
for(c = 0, p = text; p = strtok(p, delimiter); p = NULL)
++c;//count elements
ret = malloc(sizeof(char*)*(c+1));//+1 for NULL
if(ret==NULL){
free(text);
return NULL;
}
strcpy(text, str);//restore
array=ret;
for(p = text; p = strtok(p, delimiter); p = NULL)
*array++ = strdup(p);
*array = NULL;
*len = c;
free(text);
return ret;
}
int cmp(const void *a, const void *b){
return strcmp(*(char **)a, *(char **)b);
}
void find_diff(char **a1, char **a2){//arguments has been sorted
while(*a1 || *a2){
if(*a1 && a1[1] && !strcmp(*a1, a1[1])){
++a1;//distinct
continue;
}
if(*a2 && a2[1] && !strcmp(*a2, a2[1])){
++a2;
continue;
}
if(*a1 == NULL){
puts(*a2++);
} else if(*a2 == NULL){
puts(*a1++);
} else {
int result;
if((result=strcmp(*a1, *a2)) < 0){
puts(*a1++);
} else if(result > 0){
puts(*a2++);
} else {
++a1;
++a2;
}
}
}
}
void drop(char **a){
char **tmp = a;
while(*a)
free(*a++);
free(tmp);
}

Return argument doesn't work — gives me weird error

This is a simple program that should create a substring from a string, then it should return the substring as something that can be printed out.
It's actually an exercise and only the substring function can be changed. The problem is that I can't find a return type that doesn't spark all kinds of warnings and errors.
How should I change the return type?
static void panic(const char *serror)
{
printf("%s", serror);
exit(1);
}
static void *xmalloc(size_t size)
{
void *ptr;
if (size == 0)
panic("Size is 0!\n");
ptr = malloc(size);
if (!ptr)
panic("No mem left!\n");
return ptr;
}
static char *substring(const char *str, off_t pos, size_t len)
{
char out [len];
int index;
for(index = 0; index < (pos + len); index++)
{
if(index >= pos && index < (pos + len))
{
out[index - pos] = str[index];
}
}
return out;
}
int main(int argc, char **argv)
{
char *foo = "Nicht\n";
char *bar = substring(foo, 2, 3);
printf("%s", bar);
free(bar);
return 0;
}
You invoked two undefine behavior by
dereferencing a pointer bar that points at already vanished local variable.
passing a non-NULL pointer which doesn't point at buffer allocated via malloc(), calloc() or realloc().
Also note that
You have to terminate the string by adding null character.
Your loop is not efficient.
corrected code:
static char *substring(const char *str, off_t pos, size_t len)
{
char *out = xmalloc(len + 1);
int index;
for(index = pos; index < (pos + len); index++)
{
out[index - pos] = str[index];
}
out[len] = '\0';
return out;
}

random double free or corruption (out) C

I'm facing a problem which is driving me crazy !
I have a function, this one :
void load_weapons3(t_env *e, char *name, int x, t_weapon *w)
{
char *tmp;
char *fname;
t_image i;
fname = NULL;
tmp = NULL;
tmp = ft_get_name_without_extention(name);
if (!tmp)
return ;
fname = ft_strcat(tmp, "_fire.xpm");
free(tmp);
if (!fname)
return ;
i.image = mlx_xpm_file_to_image(e->mlx_ptr, fname, &(i.x), &(i.y));
if (!i.image)
{
(*w).fire = NULL;
return ;
}
else
(*w).fire = malloc(sizeof(t_weaponfire) * QTY_OF_FIRE);
i.image_data = mlx_get_data_addr(i.image,
&(i.bpp),
&(i.size_line),
&(i.endian));
i.image_tab = get_image_tab(i);
load_weapon_fire(e, x, i);
printf("%s\n", fname);
free(fname);
}
Other parts of code that may be relevant :
int ft_strlen(char *str)
{
int i;
i = 0;
while (str[i])
i++;
return (i);
}
char *ft_strcpy(char *str)
{
int i;
int j;
char *cpystr;
j = 0;
i = ft_strlen(str);
cpystr = malloc(sizeof(char) * (i + 1));
while (j < i)
{
cpystr[j] = str[j];
j++;
}
cpystr[j] = '\0';
return (cpystr);
}
char *ft_get_name_without_extention(char *fullpath)
{
char *str;
int i;
i = ft_strlen(fullpath);
str = ft_strcpy(fullpath);
while (i)
{
if (str[i] == '.')
{
str[i] = '\0';
return (str);
}
i--;
}
free(str);
return (NULL);
}
char *ft_strcat(char *str1, char *str2)
{
int i;
int len1;
int len2;
char *str;
i = 0;
str = NULL;
if (!str1 || !str2)
return (NULL);
len1 = ft_strlen(str1);
len2 = ft_strlen(str2);
str = malloc(sizeof(char) * (len1 + len2 + 1));
if (!str)
return (NULL);
while (i < len1)
str[i] = str1[i++];
len1 = 0;
while (len1 < len2)
str[i + len1] = str2[len1++];
str[i + len1] = '\0';
return (str);
}
void load_weapons(t_env *e)
{
int xpm_q;
DIR *d;
struct dirent *dir;
xpm_q = ft_get_xpm_quantity("img/weapons");
printf("Xpm_q is : %d\n", xpm_q);
if (xpm_q > 0)
{
e->weapons.weapons_count = xpm_q;
e->weapons.weapons = malloc(sizeof(t_image) * (xpm_q + 1));
xpm_q--;
d = opendir("img/weapons");
if (d)
{
while ((dir = readdir(d)) != NULL)
{
load_weapons2(&xpm_q, &(e->weapons.weapons[xpm_q]), e, dir->d_name);
}
closedir(d);
}
}
e->weapons.selected_weapon = 0;
}
void load_weapons2(int *xpm_quantity, t_weapon *w, t_env *e, char *n)
{
char *fname;
t_image *i;
if (!ft_have_extension(".xpm\0", n) || ft_have_extension("_fire.xpm\0", n))
return ;
i = &(w->image);
fname = ft_strcat("img/weapons/", n);
i->name = ft_strcpy(n);
i->image = mlx_xpm_file_to_image(e->mlx_ptr, fname, &(i->x), &(i->y));
i->image_data = mlx_get_data_addr(i->image,
&(i->bpp),
&(i->size_line),
&(i->endian));
i->image_tab = get_image_tab((*i));
load_weapons3(e, fname, *xpm_quantity, w);
free(fname);
(*xpm_quantity)--;
}
And sometimes (really randomly) I get a "double free or corruption (out)", that appears to occur when I free fname pointer. The fact is I'm not double freeing it, and printf prints it without any problem...
If someone has a clue...
I'm using gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4, running in VirtualBox.
Thanks for reading !
Your code is horrible, and you still haven't posted your typedefs and struct-definitions, which will become relevant in the following rant:
So, in load_weapons(), you malloc() an array,
e->weapons.weapons = malloc(sizeof(t_image) * (xpm_q + 1));
the contents of which are presumably supposed to be of type t_image. Then you pass a pointer to the second-to-last valid object of the array to load_weapons2() (great, descriptive name),
load_weapons2(&xpm_q, &(e->weapons.weapons[xpm_q]), e, dir->d_name);
but wait! What was load_weapon2()'s prototype again?
void load_weapons2(int *, t_weapon *, t_env *, char *)
that's no t_image*, that's a t_weapon*! Shock and awe, you then somehow extract a t_image* out of a t_weapon* that was really a t_image* in the first place,
t_image *i;
i = &(w->image);
The only way that last line makes sense is if t_weapon has a member t_image, which obviously necessitates sizeof(t_weapon) >= sizeof(t_image). So, unless t_image is the only member of t_weapon, you've allocated insufficient space.
And now for some completely unsolicited advice: complete rewrite.

Resources