Need help i get segmentation fault in program in C - 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

Related

Detect the head node of linked list

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.

C Reallocation of 2d array function

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++;
}

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.

Why did this worked on someone and else not me? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I got this code:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <dirent.h>
#include <stdlib.h>
#define W 1031
#define B 256
struct position {
int x;
int y;
struct position *next;
};
struct wordFiles {
char *fileName;
struct position *cor;
struct wordFiles *next;
};
struct wordTree {
char *word;
struct wordFiles *files;
struct wordTree *left;
struct wordTree *right;
};
struct wordTree *hashTable[W];
typedef struct wordFiles *files_Ptr;
typedef struct position *pos_ptr;
typedef struct wordTree *wordTreePtr;
long int power(int a, long b){
long int value,i;
value = 1;
for (i = 0; i < b; i++)
value *= a;
return value;
}
int hashValue (char *word){
long int i=0,s=0,n;
n = strlen(word);
for (i=0; i<n; i++){
s += power(B,n-i-1) * word[i];
}
return (s%W);
}
void readword(char *word , FILE *curr_file, int *x_axis, int *y_axis, int *newline, int *endfile){
char c;
c = (char) malloc(sizeof(char));
if ((fscanf(curr_file, "%s", word))!=1 || fscanf(curr_file, "%c", &c)!=1){
*endfile=1;
}
*x_axis += strlen(word);
if (strlen(word)==1 && c=='\n'){
*newline = 1;
return;
}
if (c==' ') {
*x_axis +=1;
}
else if (c=='\n') {
*newline = 1;
}
return;
}
void coordinateslistInsert (pos_ptr *lp,int x, int y){
pos_ptr prev,curr;
prev = NULL;
curr = *lp;
while (curr != NULL){
prev = curr;
curr = curr->next;
}
pos_ptr n = (pos_ptr) malloc(sizeof(struct position));
if (n == NULL) {
printf("Out of memory\n");
return;
}
n->next = NULL;
n->x = x;
n->y = y;
if (prev==NULL) {
*lp = n;
}
else {
prev->next = n;
}
return;
}
void filelistInsert (files_Ptr *lp, char *filename, int x, int y, int k) {
files_Ptr prev, curr;
prev = NULL;
curr = *lp;
if ( curr!=NULL && k == 1 && strcmp(curr->fileName, filename) == 0 ){
coordinateslistInsert(&(*lp)->cor, x, y);
return;
}
while (curr != NULL){
prev = curr;
curr = curr->next;
}
files_Ptr n = (files_Ptr)malloc(sizeof(struct wordFiles));
if (n == NULL) {
printf("Out of memory\n");
return;
}
n->fileName = filename;
n->next = NULL;
coordinateslistInsert (&(*n).cor , x ,y);
if (prev==NULL) {
*lp = n;
}
else {
prev->next = n;
}
return;
}
void treeBalancedInsert (wordTreePtr *curr_tree, char *word, char *filename, int x, int y) {
int k=0;
if (*curr_tree == NULL) {
*curr_tree =(wordTreePtr) malloc(sizeof(struct wordTree));
if (*curr_tree == NULL) {
printf("Out of memory\n");
exit(1);
}
(*curr_tree)->word=malloc(30*sizeof(char));
(*curr_tree)->left = (*curr_tree)->right = NULL;
strcpy((*curr_tree)->word,word);
filelistInsert (&(*curr_tree)->files , filename,x,y,k);
}
else {
if (strcmp((*curr_tree)->word,word) == 0){
k=1;
filelistInsert (&(*curr_tree)->files , filename,x,y,k);
return;
}
else if (strcmp((*curr_tree)->word,word) < 0)
treeBalancedInsert(&(((*curr_tree)->left)), word, filename, x, y);
else
treeBalancedInsert(&(((*curr_tree)->right)), word, filename,x ,y);
}
}
void search (char *word, int h_value, struct wordTree *hashtable[]){
wordTreePtr n = hashTable[h_value];
while(n!=NULL && strcmp ( n->word , word ) !=0){
if (strcmp ( n->word , word ) > 0 ){
n = n->right;
}
else if(strcmp ( n->word , word ) < 0){
n = n->left;
}
}
if (n==NULL){
printf("NOT FOUND");
return;
}
printf("%s\n",n->word);
files_Ptr k = n->files;
while (k!=NULL) {
pos_ptr q = k->cor ;
while (q!=NULL) {
printf("%s(%d,%d)\n",k->fileName,q->y,q->x);
q = q->next;
}
k = k->next;
}
return;
}
int main(int argc, char *argv[])
{
int j,i;
for (i=0; i<W; i++){
hashTable[i] = NULL;
}
for (j=1; j<argc; j++){
FILE *curr_file=fopen(argv[j], "r+");
int h_value = 0, x_axis = 1, y_axis=1, newline=0,endfile=0;
if (curr_file == NULL) {
perror("Error: ");
return (-1);
}
char *word=NULL , *filename;
filename = (char *) malloc(30*sizeof(char));
filename = argv[j];
while (endfile!=1){
word = (char *) malloc(20*sizeof(char));
readword(word, curr_file, &x_axis, &y_axis, &newline, &endfile);
h_value = hashValue(word);
treeBalancedInsert(&hashTable[h_value], word, filename, x_axis-(unsigned)strlen(word)-1, y_axis);
if (newline==1){
y_axis +=1;
x_axis=1;
newline=0;
}
}
fclose(curr_file);
free(word);
}
char *wordToSearch;
wordToSearch = (char *) malloc(20*sizeof(char));
scanf("%s",wordToSearch);
search(wordToSearch,hashValue(wordToSearch),hashTable);
return 0;
}
and it was written on a mac, and supposedly works. But when i compile and run on my machine it just wont.
What it does is it takes text files as arguments and sorts the words in binary trees which are placed in the hashtable depending the hashvalue of the word. And then you can type a word and it tells you the coordinates it appears and which files.
Anyway, debugging on eclipse step by step stucks at the (curr=curr->next) of the filelistInsert and code blocks shows 2 more problems, one at the treebalancedinsert function where it calls for the filelistinsert function and at the main when it calls for the treebalancedinsertfunction.
I cant find what's wrong in the filelistinsert and im short on time. (i know it's an awful question, but im desperate)
Change:
char c;
c = (char) malloc(sizeof(char));
to
char c;
Note: this is an error in your program but it is does not explain why your program is crashing.
Elsewhere:
filename = (char *) malloc(30*sizeof(char));
filename = argv[j];
It is a memory leak and also if you then suppose filename to be an array of 30 characters you might have troubles.
I see several problems.
The first thing that has alarm bells going off in my head are lines like
(*curr_tree)->word=malloc(30*sizeof(char));
and
word = (char *) malloc(20*sizeof(char));
If you read any word that's longer than 19 characters from your input file, you're going to have a buffer overflow, which will cause heartburn at some point. I'm reasonably sure that this is the source of your problem (when I run this program on its own source text, I start getting segfaults after reading "(*curr_tree)->word=malloc(30*sizeof(char));", most likely because we overflow a 20-character buffer and clobber something else.
The readword function should decide how much memory to allocate for a word based on the contents of the input file. This means you're going to have to make the readword function a bit smarter, and have it allocate/reallocate a buffer as it's reading input, something like the following:
void readword(char **word , FILE *curr_file, int *x_axis, int *y_axis, int *newline, int *endfile){
int c;
size_t bufLen = 0;
const size_t bufExtent=10;
size_t idx = 0;
*word = NULL;
/**
* Read input one character at a time until we see a space or EOF
*/
while ( ( c = fgetc( curr_file ) ) != EOF && !isspace( c ))
{
/**
* Are we at the end of our buffer?
*/
if ( idx == bufLen )
{
/**
* Extend the buffer
*/
char *tmp = realloc( *word, bufLen + bufExtent );
if ( tmp )
{
bufLen += bufExtent;
*word = tmp;
}
else
{
fprintf( stderr, "readword: Could not allocate memory to extend word\n" );
return;
}
}
(*word)[idx++] = c;
}
/**
* If we read a string, 0-terminate it
*/
if ( *word )
{
(*word)[idx] = 0;
*x_axis += strlen(*word);
}
However, even with this I'm still getting runtime errors, so there are other time bombs hiding in this code.
Then there's this:
filename = (char *) malloc(30*sizeof(char));
filename = argv[j];
This does not copy the contents of argv[j] to the memory you just allocated; instead, it assigns the pointer value of argv[j] to filename, overwriting the pointer to the memory you just allocated, leading to a memory leak. And again, you're picking an arbitrary length for the filename. Try something like the following:
filename = malloc( strlen( argv[j] ) + 1 );
strcpy( filename, argv[j] );
Style nit:
Hiding pointer types behind typedefs is not recommended, unless the type is meant to be opaque and never derferenced directly. If I see the * in the object declaration, I immediately know how it's supposed to be used in an expression. Using a foo_ptr typedef may make the code scan a little better, but it hinders undersatnding IMO. I've been bitten by this enough over the years to where I avoid using typedefs in general.

How to get only *.txt filenames from directory in c and write it to char ** array?

Its an extension of my previous question: How can I get only txt files from directory in c?. Now I want to save those filenames (I dont really know how many of them are in the dir) to char ** array. I figured out a solution (kind of) but then I realized that I need not a char* but char ** (I know, stupid me :])
Anyway, I got segmentation fault [core dumped] with this code:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>
#include <stdbool.h>
char* allocMemory(int n)
{
char *tab = (char *) malloc(n*sizeof(char));
return tab;
}
void freeMemory(char **tab, int n, int m)
{
int i=0;
for(i=0; i<m; i++)
free(tab[i]);
free(tab);
tab = NULL;
}
bool hasTxtExtension(char const *filename)
{
size_t len = strlen(filename);
return len > 4 && strcmp(filename + len - 4, ".txt") == 0;
}
char** getTxtFilenames(const char *dirname)
{
DIR *directory = NULL;
struct dirent *ent = NULL;
int fileCounter = 0;
char **txtFiles = allocMemory(1);
char **moreTxtFiles = allocMemory(1);
directory = opendir (dirname);
if(directory == NULL)
return NULL;
int i = 0;
while ((ent = readdir (directory)) != NULL)
{
if(hasTxtExtension(ent->d_name))
{
fileCounter ++;
moreTxtFiles = (char**) realloc (txtFiles, fileCounter * sizeof(char*));
if(moreTxtFiles[i] != NULL)
{
txtFiles = moreTxtFiles;
txtFiles[i] = allocMemory(strlen(ent->d_name));
txtFiles[i][fileCounter - 1] = ent->d_name;
}
else
{
freeMemory(txtFiles, 1, fileCounter);
return NULL;
}
}
i ++;
}
if(closedir(directory) < 0)
return NULL;
return txtFiles;
}
int main(int argc, char **argv)
{
char **txtFilenames = getTxtFilenames("dir");
if(txtFilenames == NULL)
return -1;
printf("%s\n", txtFilenames[0][1]);
return 0;
}
EDIT:
I also tried this: (notice that Im a little bit confused with those not-lovely char arrays in C, argh :/)
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>
#include <stdbool.h>
char* allocMemory(int n)
{
char *tab = (char *) malloc(n*sizeof(char));
return tab;
}
void freeMemory(char *tab)
{
free(tab);
tab = NULL;
}
bool hasTxtExtension(char const *filename)
{
size_t len = strlen(filename);
return len > 4 && strcmp(filename + len - 4, ".txt") == 0;
}
char* getTxtFilenames(const char *dirname)
{
DIR *directory = NULL;
struct dirent *ent = NULL;
int fileCounter = 0;
char *txtFiles = NULL;
char *moreTxtFiles = NULL;
directory = opendir (dirname);
if(directory == NULL)
return NULL;
while ((ent = readdir (directory)) != NULL)
{
if(hasTxtExtension(ent->d_name))
{
fileCounter ++;
moreTxtFiles = (char*) realloc (txtFiles, fileCounter * sizeof(char));
if(moreTxtFiles != NULL)
{
txtFiles = moreTxtFiles;
txtFiles[fileCounter - 1] = ent->d_name;
}
else
{
freeMemory(txtFiles);
return NULL;
}
}
}
if(closedir(directory) < 0)
return NULL;
return txtFiles;
}
int main(int argc, char **argv)
{
char **txtFilenames = getTxtFilenames("dir");
if(txtFilenames == NULL)
return -1;
printf("%s\n", txtFilenames[0]);
return 0;
}
txtFilenames[0][1] is a character, not a string.
txtFiles[i][fileCounter - 1] is a character, but ent->d_name is a
string.
I don't understand why you are using two index (i and fileCounter). Just use an array of strings.
You should also include <string.h>.
The solution is simpler:
#include <direct.h>
#include <stdlib.h>
#include <string.h>
char **f(const char *s)
{
char **p = NULL;
DIR *dir;
struct dirent *ent;
size_t i = 0;
dir = opendir(s);
while ((ent = readdir(dir)) != NULL) {
if (hasTxtExtension(ent->d_name)) {
p = realloc(p, (i + 1) * sizeof(char *));
p[i] = malloc(strlen(ent->d_name) + 1);
strcpy(p[i], ent->d_name);
++i;
}
}
closedir(dir);
return p;
}
Here is a non-exhaustive list to improve this code:
Handle reallocation errors: if realloc fail, there is a memory leak.
Handle directory errors: especially, treat the case where s is a bad directory path.
Optimize reallocations (don't use realloc with each iteration).
Aside from the questionable indexing Kirilenko pointed out, your first (and core) error is:
char **txtFiles = allocMemory(1);
char **moreTxtFiles = allocMemory(1);
Which seems innocent enough, but allocMemory is defined as:
char* allocMemory(int n)
{
char *tab = (char *) malloc(n*sizeof(char));
return tab;
}
Both txtFiles and moreTxtFiles are pointers to pointers; not pointers to chars. You're returning a pointer to a single allocated char, then storing it in a pointer that expects it to be a pointer to a pointer.
For your case, don't use allocMemory for allocating list entries. Just use it for allocating your strings.

Resources