random double free or corruption (out) C - 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.

Related

Why is the integer in the struct a garbage values even though it was changed?

So, I implemented split in C, now I know strtok exists, but I wanted to implement it, so my function returns a struct that has the string array and the length, which is decided by the number of times the delimiter occurs and whether it's the first value or not, here's the code.
split.h
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int count_delm(char *, char);
char *make_str(char);
struct split_output {
char **arr;
int size;
};
typedef struct split_output split_arr;
split_arr *split(char *, char);
split.c
#include "split.h"
int count_delm(char *str, char delm) {
register int lpvar = 0;
register int counter = 0;
while (str[lpvar] != '\0') {
if (str[lpvar] == delm) {
counter++;
}
lpvar++;
}
return counter;
}
char *make_str(char ch) {
char *ret_str = (char *)malloc(2);
ret_str[0] = ch;
ret_str[1] = '\0';
return ret_str;
}
split_arr *split(char *str, char delm) {
int num_delm = count_delm(str, delm);
char **final_arr;
register int lpvar = 0;
register int arr_counter = 0;
char *concat_str = (char *)malloc(2);
int ret_size = 0;
if (str[0] == delm) {
concat_str = make_str(str[1]);
final_arr = (char **)malloc(sizeof(char *) * (num_delm));
ret_size = num_delm;
lpvar++;
} else {
concat_str = make_str(str[0]);
final_arr = (char **)malloc(sizeof(char *) * (num_delm + 1));
ret_size = num_delm + 1;
}
while (1) {
if (str[lpvar + 1] != '\0') {
if (str[lpvar + 1] != delm) {
concat_str = strcat(concat_str, make_str(str[lpvar + 1]));
lpvar++;
} else {
final_arr[arr_counter] = concat_str;
arr_counter++;
if (str[lpvar + 2] != '\0') {
lpvar++;
lpvar++;
concat_str = make_str(str[lpvar]);
}
}
} else {
arr_counter++;
final_arr[arr_counter] = concat_str;
printf("%s is the last at pos %d\n", concat_str, arr_counter);
break;
}
}
split_arr *ret_struct = (split_arr *)malloc(sizeof(split_arr));
(*ret_struct).size = ret_size;
(*ret_struct).arr = final_arr;
return ret_struct;
}
That was the code of the split implementation, here's the code that tests it.
test.c
#include "split.h"
int main() {
char *x = "lryabruahsdfads";
split_arr output = *(split(x, 'a'));
char **read = output.arr;
int len = output.size;
int loop = 0;
printf("size: %d", len - 1);
for (loop = 0; loop < len; loop++) {
puts(*(read + loop));
}
return 0;
}
Here's the output when executed:
ds is the last at pos 4
size: 3lry
bru
hsdf
Segmentation fault (core dumped)
Why is output.size 3lry? I de-referenced the struct pointer to get the struct so there's nothing wrong with that. I can't find the error, I've been trying to debug for almost an hour.
In your split.c file over here:
else{
arr_counter++; //comment this line
final_arr[arr_counter]=concat_str;
printf("%s is the last at pos %d\n",concat_str,arr_counter);
break;
}
You are incrementing variable arr_counter which you should not because you already incremented it inside the if. Just comment out this line and your code works fine.
And your output is fine just add a line return to the printf statements like:
printf("size: %d \n",len-1);

Why is one of my struct members undefined after attempting to change it in a function? I passed the struct as reference

I am writing code for a search_tree() function which fills a chArray struct (dynamic char array) with all the files in a directory and its sub-directories.
However, I'm having problems with the add_elements() function, which is meant to add elements to the char array and adjust its size accordingly.
The array.size member is undefined after the function call, even though I passed the chArray variable as reference to the function.
Why is this happening?
-Apart from this I'm having memory allocation errors, but I'm nearly sure the reason for this is this issue with array.size being undefined.
Thank you for any help!!
P.S. I've included my entire code below, sorry for all the random print statements and weird names - this was me trying to figure out what was wrong.
//
// Created by mario on 05/03/2022.
//
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <string.h>
#include <stdarg.h>
#include <sys/stat.h>
#include <stddef.h>
#ifndef errno
extern int errno;
#endif
typedef struct {
int init;
int numEls;
size_t size;
char **elements;
} chArray;
void initArray(chArray *arr, int n, ...) {
size_t c_size = 0;
va_list ptr;
arr = malloc(sizeof(chArray));
*arr = (chArray) {.init = 1, .numEls = n, .size = sizeof(chArray), .elements = NULL};
va_start(ptr, n);
for (int i = 0; i < n; i++) {
char *arg = va_arg(ptr, char*);
c_size += strlen(arg) + 1;
printf("%lu\n", c_size);
if (i == 0) {
arr->elements = (char **) malloc(strlen(arg) + 1);
}
else {
arr->elements = realloc(arr->elements, arr->size + strlen(arg) + 1);
}
*(arr->elements + i) = arg;
}
va_end(ptr);
arr->size = c_size + offsetof(chArray, elements);
printf("%lu\n", arr->size);
}
void add_elements(chArray *arr, int n, ...) {
va_list ptr;
size_t new_size = arr->size;
va_start(ptr, n);
for (int i = 0; i < n; i++) {
char *f_arg = va_arg(ptr, char *);
new_size += strlen(f_arg) + 1;
}
va_end(ptr);
arr = realloc(arr, new_size);
va_start(ptr, n);
for (int i = arr->numEls; i < n+arr->numEls; i++) {
char *arg = va_arg(ptr, char*);
arr->size += strlen(arg) + 1;
if (i == 0) {
arr->elements = (char **) malloc(strlen(arg) + 1);
}
else {
arr->elements = realloc(arr->elements, arr->size + strlen(arg) + 1);
}
*(arr->elements + i) = arg;
}
va_end(ptr);
arr->numEls += n;
}
int search_tree(char *tree, char *contains, chArray *ends) {
struct dirent *entry;
DIR *dir;
struct stat buff;
mode_t mode;
char *not1 = ".";
char *not2 = "..";
unsigned long int tree_length = strlen(tree);
char *last = tree + tree_length - 1;
#ifdef _WIN32
if (last != '\\') {
char *slash = "\\\0";
#else
if (*last != '/') {
char *slash = "/\0";
#endif
if (*last == '\\') {
char *temp = (char *) malloc(tree_length + 1);
memset(temp, '\0', tree_length + 1);
strncpy(temp, tree, tree_length - 1);
tree = 0;
tree = (char *) malloc(tree_length + 2);
strcpy(tree, temp);
strcat(tree, slash);
free(temp);
}
else {
char *temp = (char *) malloc(tree_length + 2);
memset(temp, '\0', tree_length + 2);
strcpy(temp, tree);
tree = 0;
tree = (char *) malloc(tree_length + 2);
strcpy(tree, temp);
strcat(tree, slash);
free(temp);
}
}
if (ends->init != 1) {
printf("Once\n");
initArray(ends, 0);
}
if ((dir = opendir(tree)) == NULL) {
perror("An error occurred");
fprintf(stderr, "Errno = %d", errno);
return -1;
}
while ((entry = readdir(dir)) != NULL) {
size_t length = strlen(tree) + strlen(entry->d_name) + 1;
char *file_path = (char *) malloc(length);
memset(file_path, '\0', length);
strcpy(file_path, tree);
strcat(file_path, entry->d_name);
if (stat(file_path, &buff) != -1) {
mode = buff.st_mode;
if (S_ISDIR(mode) && (strcmp(entry->d_name, not1) != 0) && (strcmp(entry->d_name, not2) != 0)) {
search_tree(file_path, contains, ends);
for (int i = 0; i < ends->numEls; i++) {
printf("%s\n", *(ends->elements));
}
} else if (S_ISREG(mode)) {
if (contains == NULL) {
add_elements(ends, 1, file_path);
for (int i = 0; i < ends->numEls; i++) {
printf("%s\n", *(ends->elements));
}
}
else {
if (strstr(file_path, contains) != NULL) {
add_elements(ends, 1, file_path);
for (int i = 0; i < ends->numEls; i++) {
printf("%s\n", *(ends->elements));
}
}
}
}
}
else {
perror("An error occurred");
fprintf(stderr, "Errno = %d", errno);
return -1;
}
}
closedir(dir);
return 0;
}
int main(int argc, char *argv[]) {
char *path = "/Users/mario/python";
char *toComp = "python";
// printf("%d\n", strcmp(strstr(path, "python"), toComp));
chArray test;
initArray(&test, 3, "Hello", "There", "Goodbye");
printf("%lu\n", test.size);
add_elements(&test, 10, "Soyez", "Jiduan", "Chifa3n", "Chifa4n", "Chifa5n", "Chif6an", "Chifan7", "Chifa8n", "Chifan9", "Chifan10");
for (int i = 0; i < 6; i++) {
printf("%s\n", *(test.elements + i));
}
chArray ends;
char *tree = "/Users/mario/Desktop";
search_tree(tree, ".py", &ends);
printf("%lu\n", sizeof(ends));
printf("%s\n%s\n", *ends.elements, *(ends.elements + 1));
chArray *random = (chArray * ) malloc(48);
printf("%lu\n", sizeof(*random));
return 0;
}
Output:
36
4486016032
search_tree(4025,0x117c5a600) malloc: *** error for object 0x7ff7b48d0838: pointer being realloc'd was not allocated
search_tree(4025,0x117c5a600) malloc: *** set a breakpoint in malloc_error_break to debug
The 36 is the array's size printed from within the add_elements() function, and the second number is the same but printed just after the function.
What is going on?

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

Unexpected Character getting added to the end of string in C

IN my code, I have a random character that appears when I send a char array through a function, like so:
struct TokenizerT_ { //Defintion of the struct
char * sep;
char * toks;
};
TokenizerT *TKCreate(char *separators, char *ts) {
TokenizerT * inu = malloc(sizeof(*inu));
inu->toks = malloc(sizeof(char)); //Initialize char array that will store the tokens
strcpy(inu->toks, hr);
return inu;
}
.......
best = "sein";
printf("%s\n", best);
char * rondo = malloc(sizeof(char));
printf("%s\n", rondo);
TokenizerT * Ray = TKCreate(copy, rondo); /
printf("%s\n", Ray->toks);
For the last bit, the printed out values are as follows:
sein
sein
sein?
Why is the question mark appearing? This is usually a random character and not always a question mark.
Edit: Full code, really desperate
struct TokenizerT_ { //Defintion of the struct
char * sep;
char * toks;
};
char nulines[10] = "ntvbrfa\\\""; //for the arguments with backslashes
char resp[37] = "0x0a0x090x0b0x080x0d0x0c0x070x5c0x22";
typedef struct TokenizerT_ TokenizerT;
TokenizerT *TKCreate(char *separators, char *ts) {
if (ts==NULL) { //If there are no tokens to be parsed (empty entry)
return NULL;
}int lim = 1;
char yr[strlen(separators)]; //Initializes delimitors
yr[0] = *separators;
if(strlen(separators)>0){
int h =1;
char zmp = *(separators+h);
for(h=1; h<strlen(separators); h++){
zmp = *(separators+h);
int z=0;
for (z=0; z<lim; z++) {
if (zmp==yr[z]) {
z=-1;
break;
}
}
if(z>-1){
yr[lim] = zmp;
lim++;}
else{
continue;
} //yr is local variable that contains delimitors
}}
TokenizerT * inu = malloc(sizeof(*inu)); //Creates TokenizerT
inu->sep = malloc((int)strlen(yr)*sizeof(char));
strcpy(inu->sep, yr);
char hr [strlen(ts)];
lim = 0; int q = 0; int wy=0;
for(q=0; q<strlen(ts); q++){
if(ts[q]=='\\'){
q++;
for(wy = 0; wy<strlen(nulines); wy++){
if (nulines[wy]==ts[q]) {
hr[lim] = '['; hr[++lim] = '0'; hr[++lim] = 'x'; hr[++lim] = resp[wy*4+2];
hr[++lim] = resp[wy*4+3];
hr[++lim] = ']'; lim++;
break;
}
}
continue;
}
else{
hr[lim] = ts[q];
lim++;
}
}
inu->toks = (char *)malloc(sizeof(char) * strlen(hr) + 1);
strcpy(inu->toks, hr); //Makes copy
return inu;
}
void TKDestroy(TokenizerT *tk) {
free(tk->toks); //Free Memory associated with the token char array
free(tk->sep); //Free Memory associated with the delimitor char array
free(tk); //Free Memory associated with the tokenizer
}
char *TKGetNextToken(TokenizerT *tk) {
char * stream = tk->toks;
char * dels = tk->sep;
/*The following two lines intialize the char array to be printed
as well as the integers to be used in the various loops*/
char * temps = malloc(sizeof(char)); int g = 0;
int z = 0, x= 0, len = 0;
if (strlen(dels)==0) {
return stream;
}
for(z = 0; z<strlen(stream); z++){
char b = *(stream+z);
for(x = 0; x<strlen(dels); x++){
len = (int)strlen(temps);
char c = *(dels+x);
if(c==b){ //Here, the current character is a delimitor
g = -1;
break;
}
}
if (g==-1) { //If delimitor, then return the current token
return temps;
}
*(temps+len) = b;
}
len = (int)strlen(temps);
*(temps+len) = '\0'; //Returns the string with the null character ending it
return temps;
}
void TKN(TokenizerT * tin, int sum){
char * tmp = TKGetNextToken(tin);
char * copy = malloc(sizeof(char));
strcpy(copy, tin->sep);
int difference = (int)strlen(tmp)+1;
sum = sum-difference;
char * best = malloc(sizeof(char));
strcpy(best, tin->toks + difference);
if((int)strlen(tmp)>0){
printf("%s\n", tmp);
}
TKDestroy(tin);
tin = TKCreate(copy, best);
while(sum>0){
tmp = TKGetNextToken(tin);
if((int)strlen(tmp)>0){
printf("%s\n", tmp);
}
difference = (int)strlen(tmp)+1;
sum = sum-difference;
free(best);
best = malloc(sizeof(char));
strcpy(best, tin->toks + difference);
TKDestroy(tin);
tin = TKCreate(copy, best);
}
free(copy);
free(best);
free(tmp);
TKDestroy(tin); //Freeing up memory associated with the Tokenizer
return;
}
int main(int argc, char **argv) {
if(argc<2){
printf("%s\n", "Not enough arguments");
return 0;
}
else if(argc>3){
printf("%s\n", "Too many arguments");
return 0;
}
else{
char * arr = argv[1]; //Represents delimitors
char * y = argv[2]; //Represents string to be tokenized
TokenizerT * jer = TKCreate(arr, y); //Create and initialize tokenizer
//printf("%s\n", jer->toks);
TKN(jer, (int)strlen(jer->toks));
}
return 0;
}
In most of your malloc, you don't only allocate for one character:
malloc(sizeof(char))
while you should write:
malloc(sizeof(char) * n + 1)
Where n is the length of string that you want and +1 is for the terminating null character. You are seeing the random character it is because both C and C++ use null character as the termination for string datatype and by not allocating correctly, it starts for read until it gets to null.
struct TokenizerT_ { //Defintion of the struct
char * sep;
char * toks;
};
char nulines[10] = "ntvbrfa\\\""; //for the arguments with backslashes
char resp[37] = "0x0a0x090x0b0x080x0d0x0c0x070x5c0x22";
typedef struct TokenizerT_ TokenizerT;
TokenizerT *TKCreate(char *separators, char *ts) {
if (ts==NULL) { //If there are no tokens to be parsed (empty entry)
return NULL;
}int lim = 1;
char yr[strlen(separators)]; //Initializes delimitors
yr[0] = *separators;
if(strlen(separators)>0){
int h =1;
char zmp = *(separators+h);
for(h=1; h<strlen(separators); h++){
zmp = *(separators+h);
int z=0;
for (z=0; z<lim; z++) {
if (zmp==yr[z]) {
z=-1;
break;
}
}
if(z>-1){
yr[lim] = zmp;
lim++;}
else{
continue;
} //yr is local variable that contains delimitors
}}
TokenizerT * inu = (TokenizerT *)malloc(sizeof(*inu)); //Creates TokenizerT
inu->sep = (char *)malloc((int)strlen(yr)*sizeof(char));
strcpy(inu->sep, yr);
char hr [strlen(ts)];
lim = 0; int q = 0; int wy=0;
for(q=0; q<strlen(ts); q++){
if(ts[q]=='\\'){
q++;
for(wy = 0; wy<strlen(nulines); wy++){
if (nulines[wy]==ts[q]) {
hr[lim] = '['; hr[++lim] = '0'; hr[++lim] = 'x'; hr[++lim] = resp[wy*4+2];
hr[++lim] = resp[wy*4+3];
hr[++lim] = ']'; lim++;
break;
}
}
continue;
}
else{
hr[lim] = ts[q];
lim++;
}
}
inu->toks = (char *)malloc(sizeof(char) * strlen(hr) + 1);
strcpy(inu->toks, hr); //Makes copy
return inu;
}
void TKDestroy(TokenizerT *tk) {
free(tk->toks); //Free Memory associated with the token char array
free(tk->sep); //Free Memory associated with the delimitor char array
free(tk); //Free Memory associated with the tokenizer
}
char *TKGetNextToken(TokenizerT *tk) {
char * stream = tk->toks;
char * dels = tk->sep;
/*The following two lines intialize the char array to be printed
as well as the integers to be used in the various loops*/
char * temps = (char *)malloc(sizeof(char)); int g = 0;
int z = 0, x= 0, len = 0;
if (strlen(dels)==0) {
return stream;
}
for(z = 0; z<strlen(stream); z++){
char b = *(stream+z);
for(x = 0; x<strlen(dels); x++){
len = (int)strlen(temps);
char c = *(dels+x);
if(c==b){ //Here, the current character is a delimitor
g = -1;
break;
}
}
if (g==-1) { //If delimitor, then return the current token
return temps;
}
*(temps+len) = b;
}
len = (int)strlen(temps);
*(temps+len) = '\0'; //Returns the string with the null character ending it
return temps;
}
void TKN(TokenizerT * tin, int sum){
char * tmp = TKGetNextToken(tin);
char * copy = (char *)malloc(sizeof(char));
strcpy(copy, tin->sep);
int difference = (int)strlen(tmp)+1;
sum = sum-difference;
char * best = (char *)malloc(sizeof(char));
strcpy(best, tin->toks + difference);
if((int)strlen(tmp)>0){
printf("%s\n", tmp);
}
TKDestroy(tin);
tin = TKCreate(copy, best);
while(sum>0){
tmp = TKGetNextToken(tin);
if((int)strlen(tmp)>0){
printf("%s\n", tmp);
}
difference = (int)strlen(tmp)+1;
sum = sum-difference;
free(best);
best = (char *)malloc(sizeof(char));
strcpy(best, tin->toks + difference);
TKDestroy(tin);
tin = TKCreate(copy, best);
}
free(copy);
free(best);
free(tmp);
TKDestroy(tin); //Freeing up memory associated with the Tokenizer
return;
}
int main(int argc, char **argv) {
if(argc<2){
printf("%s\n", "Not enough arguments");
return 0;
}
else if(argc>3){
printf("%s\n", "Too many arguments");
return 0;
}
else{
char * arr = argv[1]; //Represents delimitors
char * y = argv[2]; //Represents string to be tokenized
TokenizerT * jer = TKCreate(arr, y); //Create and initialize tokenizer
//printf("%s\n", jer->toks);
TKN(jer, (int)strlen(jer->toks));
}
return 0;
}
char * rondo = malloc(sizeof(char));
printf("%s\n", rondo);
is a UB(Undefined behaviour) condition.
This is what you are doing:
free store(heap) -> allocate memory of size char(usually 1 byte) and get the address of that location and store it(address) in rondo.
so when you dereference rondo i.e *rondo you can legally only access the location that is of the size of char accessing anything next to it or near it is illegal.
so in printf("%s\n", rondo); what you do is tell printf that what pointer you give is a pointer to string and so print till you get a \0(NULL) character. but you did not actually do that. which means printf is actually accessing memory that was not allocated. what you saw is out of pure luck(or rather unfortunate).
you can only do this
printf("%c\n", *rondo); but even before this you have to initialize for e.g
char * rondo = malloc(sizeof(char));
*rondo = 'K';
printf("%c\n",*rondo);
but I bet you dint mean that you would have meant
char * rondo = malloc(sizeof(char)*no_of_characters_in_string+1);
where +1 is for the NULL character.
What characters you saw is not related to your program. you accessed someone else's memory(if it was allocated to some one else or OS's property).
Edit :
there is also a huge problem in you code. you are mallocing memory but are never freeing it. for small demo programs its ok(not really) but it definitely is very bad. please always associate a malloc with a free();
My advice get a good text book. it will tell you in more details about these things.

How to malloc inside a function and return pointer in C?

Below is some psudo, but I'm trying to accomplish this. The problem is as written, it returns a blank pointer.
int testFunction(char *t) {
int size = 100;
t = malloc(100 + 1);
t = <do a bunch of stuff to assign a value>;
return size;
}
int runIt() {
char *str = 0;
int str_size = 0;
str_size = testFunction(str);
<at this point, str is blank and unmodified, what's wrong?>
free(str);
return 0;
}
This works fine if I have a predefined size, such as char str[100] = "" and I don't try to malloc or free memory afterwords. I need to be able to make the size dynamic though.
I've also tried this, but seem to run into a corrupt pointer somehow.
int testFunction(char **t) {
int size = 100;
t = malloc(100 + 1);
t = <do a bunch of stuff to assign a value>;
return size;
}
int runIt() {
char *str = 0;
int str_size = 0;
str_size = testFunction(&str);
<at this point, str is blank and unmodified, what's wrong?>
free(str);
return 0;
}
Thanks!
Your test function is just a bit backward. Size should be an input. The allocated pointer should be the output:
char* testFunction(int size) {
char* p = malloc(size);
<do a bunch of stuff to assign a value>;
return p;
}
int runIt() {
char *str = 0;
int str_size = 100;
str = testFunction(str_size);
<do something>
free(str);
return 0;
}
edit
Per comment, making size an output too.
char* testFunction(int *size) {
*size = <compute size>;
char* p = malloc(size);
<do a bunch of stuff to assign a value>;
return p;
}
int runIt() {
char *str = 0;
int str_size;
str = testFunction(&str_size);
<do something>
free(str);
return 0;
}
You're nearly there with the second example, but change
int testFunction(char **t) {
...
t = malloc(100 + 1);
To
int testFunction(char **t) {
...
*t = malloc(100 + 1);
The point being that you're passing in a char**, a pointer to a pointer, so you want to assign the malloc to what that points at (a pointer).
I am also studying c++. I had a the same question. So after speaking to c++ pro at work, he suggest me to do something like this
int method(char* p) {
if (p) {
strcpy(p, "I like c++");
}
return strlen("I like c++");
}
int main()
{
char* par = NULL;
int len = method(par);
if (len > 0) {
par = (char*)malloc(len+1);
memset(par, 0, len + 1);
method(par);
cout << "ret : " << par;
}
free(par);
}

Resources