pointer being realloced was not allocated - c

I am trying to dynamically allocate an array of structs but whenever I run the program I keep getting: a.out(6487,0x7fff7ecb8300) malloc: * error for object 0x7fff6f670000: pointer being realloc'd was not allocated
* set a breakpoint in malloc_error_break to debug
struct node {
char course[25];
char category[20];
char prereq[50];
char notes[50];
};
int main(int argc, char* argv[])
{
FILE *fp;
char *filename = argv[1];
char *token;
char buffer[100];
char *del = ",\n";
int num = 5, i = 0, j =0, count = 0;
struct node *d = malloc(num * sizeof(struct node));
char** complete = malloc(num * sizeof(char*));
printf("%s\n", filename);
if( (fp = fopen(filename, "r")) == NULL )
{
printf("unable to open %s\n", filename);
exit(1);
}
while(fgets(buffer, sizeof(buffer), fp) != NULL)
{
if(count == num)
{
num = num + 5;
struct node *d = realloc(d, sizeof(d)*num);
printf("Reallocating\n");
}
token = strtok(buffer, del);
if(strncmp(token, "#", 1) != 0)
{
strcpy(d[count].course, token);
printf("%s\n", d[count].course);
strcpy(d[count].category, strtok(NULL, del));
printf("%s\n", d[count].category);
strcpy(d[count].prereq, strtok(NULL, del));
printf("%s\n", d[count].prereq);
strcpy(d[count].notes, strtok(NULL, del));
printf("%s\n", d[count].notes);
count++;
}
}

struct node *d = realloc(d, sizeof(d)*num);
You're declaring a new d variable which shadows the previous one, and feed its yet-uninitialized value to realloc.
You need to do this :
struct node *newD = realloc(d, num * sizeof *d);
if(!newD) {
// Allocation failure, do something about it and break out
} /* else */
d = newD;
Also note that I corrected the sizeof, which measured the size of the pointer, not the pointee's.

In:
struct node *d = realloc(d, sizeof(d)*num);
That declares a new variable d with initially undetermined value and passes it into realloc. Change that to:
struct node *tmp = realloc(d, sizeof(*d)*num);
if(!tmp)
; // handle error
d = tmp;

Related

realloc, for string array in C

Is there a correct way to use realloc, for when you want to add words of variable size to a string array? I am getting a segmentation fault.
Please show me what's wrong
// This function puts every word found in a text file, to a String array, **words
char **concordance(char *textfilename, int *nwords){
FILE * fp;
char *fileName = strdup(textfilename);
fp = fopen(fileName, "r");
if(fp == NULL) {
perror("fopen");
exit(1);
}
char **words = malloc(sizeof(char));
// char **words = NULL
char line[BUFSIZ];
while(fgets(line, sizeof(line), fp) != NULL){
char *word = strdup(line);
word = strtok(word, " ");
do{
words = realloc(words, (*nwords+1) * sizeof(char(*)));
words[*nwords] = word;
} while((word = strtok(NULL, " ")) != NULL);
}
return words;
}
int main(int argc, const char * argv[]) {
int *nwords = malloc(sizeof(int));
nwords = 0;
concordance("test.txt", nwords);
}
You seem to initialize nwords to 0, in a wrong way. As you have declared it as a pointer, you can not access it directly. instead, you should use the de-reference operator *.
make the following change in the main function
*nwords = 0; instead of nwords = 0;
nwords = 0 modifies the location to which nwords is pointing to, to the location with address 0, to which you have no access and can not assign.
WARNING:
It is better not to perform realloc on the same pointer, it will make the pointing location NULL if the realloc fails, leading to the loss of the previously existing data. Instead, as #David suggests, you could use a temp variable to realloc memory and then, check if it is not NULL and then assign its contents to the words pointer.
//your code
char *tmp = realloc(words, /* new size*/);
if(tmp != NULL)
words = tmp;
// your code
while using realloc you usually use it to allocate a block of data, not for a single location.
When you initiate the value of nwords, you were overwriting its pointer address, not its value.
Additionally, as the commenter says, the line char **words = malloc(sizeof(char)); is not correct. But you always re-allocate the variable words so the code still works as expected. To make it super safe you should change it to char **words = malloc(sizeof(char*));
I use the line *nwords = 0; and now it works as expected.
#define BUFSIZ 1000
#include<stdio.h>
// This function puts every word found in a text file, to a String array, **words
char **concordance(char *textfilename, int *nwords){
FILE * fp;
char *fileName = strdup(textfilename);
fp = fopen(fileName, "r");
if(fp == NULL) {
perror("fopen");
exit(1);
}
char **words = malloc(sizeof(char));
// char **words = NULL
char line[BUFSIZ];
while(fgets(line, sizeof(line), fp) != NULL){
char *word = strdup(line);
word = strtok(word, " ");
printf("word='%s'\n",word);
do{
*nwords=*nwords+1;
printf("nwords=%d\n",*nwords);
words = realloc(words, (*nwords+1) * sizeof(char(*)));
words[*nwords] = word;
} while((word = strtok(NULL, " ")) != NULL);
}
return words;
}
int main(int argc, const char * argv[]) {
int *nwords = malloc(sizeof(int));
*nwords = 0;
concordance("test.txt", nwords);
}

Why this code gives unreadable first line?

This code reads file and split it lines into array in order to compare lines elements to each other.
The problem that it gives me as the first line
)�H� 2382 2382
I think that the function char **linecontent(char *line) is the problem but I am new in C and I tried every possible solution and I have nothing.
I am very sorry for asking.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char** split(char string[],const char seps[])
{
char ** res = NULL;
char * p = strtok(string, seps);
int n_spaces = 0, i;
while (p) {
res = realloc(res, sizeof (char*) * ++n_spaces);
if (res == NULL) {
exit(-1); /* memory allocation failed */
}
res[n_spaces-1] = p;
p = strtok(NULL, seps);
}
res = realloc(res, sizeof (char*) * (n_spaces+1));
res[n_spaces] = '\0';
return res;
free(res);
}
char** readfile(char *name, int *lsize)
{
FILE *fp;
char *result;
char line[500];
char *pline = NULL;
char **lines = NULL;
int i = 0;
int l = 0;
fp = fopen(name, "r");
while (fgets(line,500, fp)) {
i++;
pline = strdup(line);
lines = (char**)realloc(lines, sizeof (char**) * (++l));
/* Add to lines */
lines[l-1] = pline;
*lsize += 1;
pline = NULL;
}
fclose(fp);
return lines;
}
char** linecontent(char *line)
{
char **linecont;
char hit[300];
strncpy(hit, line, sizeof(hit) - 1);
hit[sizeof(hit) - 1] = '\0';
linecont = split(hit, "\t");
return linecont;
}
int main()
{
char **lines = NULL;
int lsize = 0;
lines = readfile("TEMP", &lsize);
int i = 0;
while (i != lsize) {
char **linecont1;
char *thisline=lines[i];
linecont1=linecontent(thisline);
char *pname1 = linecont1[0];
char *acc1 = linecont1[1];
int start1 = atoi(linecont1[3]);
int miss1 = atoi(linecont1[4]);
printf("%s\t%s\t%d\t%d\n", pname1, acc1, start1, start1);
i++;
}
}

Load/fill a struct with char** array as a struct member, c

In the last two days i have asked a question to load struct, but i have a problem to access my struct out side my loop(a loop to load my struct). i have edited my question/and code this way:
myfile.txt
Biology,chemistry,maths,music
Mechanics,IT,Geology,music,Astronomy
football,vollyball,baseball
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define path "myfile.txt"
typedef struct student_info
{
char **cources_as_list;
} std_info;
std_info *myinfo; //a global var that will conatain student info
int line_count = 0, cource_count = 0;
char** load_file()
{
char *line = NULL;
size_t len = 0;
FILE *fp;
int indexq=0;
fp = fopen(path, "r");
if (fp == NULL)
{
perror("FILE OPEN ERROR[IN load_file]: ");
exit(1);
}
char **mydata = malloc (sizeof (char *) * 4);//aup to four elements
while (getline(&line, &len, fp) != -1)
{
strtok(line, "\n");
mydata[indexq]= strdup(line);
indexq++;
}
line_count = indexq;
return mydata;
}
char **return_cource_list(char *cources_string) {
char *token;
char **cource_list = malloc(sizeof(char *) * 10);
int index = 0;
//course_string is delimited by ",": (eg. Biology,chemistry,maths,music). parse this and add to my char ** variable.
token = strtok(cources_string, ",");
while (token != NULL)
{
cource_list[index] = strdup(token);
token = strtok(NULL, ",");
index++;
}
cource_count = index;
return cource_list;
}
int main()
{
int i, j;
char** mydata = load_file(); //returns lines as a list/char ** array from file
for (i = 0; i < line_count; i++) //line_count is the number of elements/lines in "mydata"
{
printf("line_data: %s\n",mydata[i]);//i can see all my lines!
char **std_cource_list = return_cource_list(mydata[i]);
for (j = 0; j < cource_count; j++)
{
printf("\tcourse[%d]: %s\n",j,std_cource_list[j]);//i have all my courses as a list from each line
}
//can i load my struct like this? or any option to load my struct?
myinfo[i].cources_as_list = std_cource_list;
}
// i want to see my structure elements here, (nested for loop required).
}
Am getting seg_fault error while loading my char array to my struct.
(i.e: this line: myinfo[i].cources_as_list = std_cource_list;)
You need to allocate the memory for your struct.
std_info *myinfo = malloc(sizeof(std_info));
Also don't make it global, since there is really no need for global variables in this task.
Try
std_info * myinfo = malloc(line_count * sizeof *myinfo);
This allocates memory to hold line_count objects of std_info, with myinfo pointing to the 1st.
You never allocate space for myinfo and I would suggest making it a local variable. There is almost no need for global variables except in very specific cases.
Also, you are using malloc() almost only for fixed size allocations which would be easier to manage and more efficient if you do statically in the sense that you can use arrays for that.
This might be what you're interested in
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
struct student_info
{
char **courses;
size_t size;
};
char **
load_file(const char *const path)
{
char *line;
FILE *file;
char **data;
size_t row;
size_t length;
size_t count;
file = fopen(path, "r");
if (file == NULL)
{
perror("FILE OPEN ERROR[IN load_file]: ");
return NULL; // Notify the caller that there was a problem
// but do not necessarily quit as you might
// retry with another path.
}
count = 0;
for (int chr = fgetc(file) ; chr != EOF ; chr = fgetc(file))
count += (chr == '\n') ? 1 : 0;
rewind(file);
data = malloc((count + 1) * sizeof(*data));
if (data == NULL)
{
// Perhaps notify the error
fclose(file);
return NULL;
}
data[count] = NULL; // Use as end of array delimiter
row = 0;
line = NULL;
length = 0;
while ((length = getline(&line, &length, file)) != -1)
{
// The last character is always `\n' so remove it
data[row] = malloc(length);
if (data == NULL)
{
fclose(file);
for (size_t i = row ; i >= 0 ; --i)
{
free(data[i]);
free(data);
return NULL;
}
}
data[row][length - 1] = '\0';
memcpy(data[row], line, length - 1);
++row;
}
fclose(file);
// You need to `free' this, read the documentation
free(line);
return data;
}
char **
extract_courses_as_list(const char *const input)
{
char **courses;
size_t index;
const char *tail;
const char *head;
size_t count;
head = input;
count = 0;
/* Count the number of fields to allocate memory */
while (head != NULL)
{
tail = strchr(head, ',');
if (tail != NULL)
head = tail + 1;
else
head = NULL;
count += 1;
}
index = 0;
/* Allocate memory for the list, and the sentinel */
courses = malloc((count + 1) * sizeof(*courses));
head = input;
while (head != NULL)
{
ptrdiff_t length;
/* find the next `,' in the input string */
tail = strchr(head, ',');
if (tail == NULL) /* if it's not there, it's the last one */
tail = strchr(head, '\0');
/* compute the number of characters of the field */
length = (ptrdiff_t) (tail - head);
/* allocate space to copy the string */
courses[index] = malloc(length + 1);
if (courses == NULL) /* always be safe and check */
{
for (size_t i = index ; i >= 0 ; --i)
free(courses[index]);
free(courses);
return NULL;
}
/* always remember to `null' terminate */
courses[index][length] = '\0';
/* finally, copy the string */
memcpy(courses[index], head, length);
/* check whehter it was the last field and
* update the pointer to the next one accordingly
*/
if ((tail != NULL) && (*tail != '\0'))
head = tail + 1;
else
head = NULL;
/* Don't forget the fields counter */
index++;
}
courses[count] = NULL;
return courses;
}
void
concatenate_lists(struct student_info *info, char **source)
{
char **temporary;
size_t length;
length = info->size;
for (size_t i = 0 ; source[i] != NULL ; ++i)
length++;
temporary = realloc(info->courses, length * sizeof(*temporary));
if (temporary == NULL)
return;
for (size_t i = 0 ; source[i] != NULL ; ++i)
temporary[i + info->size] = strdup(source[i]);
info->courses = temporary;
info->size = length;
}
void
free_list(char **lines)
{
if (lines == NULL)
return;
for (size_t i = 0 ; lines[i] != '\0' ; ++i)
free(lines[i]);
free(lines);
}
int
main()
{
struct student_info info;
char **lines;
lines = load_file("data.tx");
if (lines == NULL)
return -1;
info.courses = NULL;
info.size = 0;
for (size_t i = 0 ; lines[i] != NULL ; ++i)
{
char **courses;
courses = extract_courses_as_list(lines[i]);
if (courses == NULL)
continue;
concatenate_lists(&info, courses);
free_list(courses);
}
for (size_t i = 0 ; i < info.size ; ++i)
{
fprintf(stderr, "%s\n", info.courses[i]);
free(info.courses[i]);
}
free(info.courses);
free_list(lines);
return 0;
}
You will notice that I never used strdup(), the reason being that the length of the string that we want to copy is always known.

Fill a struct containing char** array as a member, C

...currently am practicing to fill a struct that contains an array(char array to store multiple elements). The scenario am trying to implement is as follows:
The general task is (to store student information, name as string and courses taken by the student as a list or char**)
student information is first loaded from file!(myfile.txt)
tokenize/parse student information and load to struct
The file that contains my student information is:
myfile.txt (each line contains student name and list of courses) delimited by ":"
Austin Barbra:Biology,chemistry,maths,music
Romio Chandra:Mechanics,IT,Geology,music,Astronomy
.
.
My main.c is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define path "myfile.txt"
typedef struct student_info
{
char *studt_name;
char *cources_as_string;
char **cources_as_list;
}std_info ;
std_info *myinfo; //a global var that will conatain student info
int student_count = 0,cource_count=0;
void load_file()
{
int i,yu,index=0;
char *line =NULL,* token = NULL;
size_t len=0;
FILE *fp;
fp =fopen(path,"r");
if(fp==NULL)
{
perror("FILE OPEN ERROR[IN load_file]: ");
return;
}
if (( myinfo = (struct student_info *) malloc( 2 * sizeof(myinfo) ) ) == NULL)//malloc for 2 students
puts ("malloc fail");
while (getline(&line, &len, fp) != -1 )
{
strtok(line,"\n");
char *token;
token = strtok(line,":");
myinfo[index].studt_name=(char * ) malloc(200 * sizeof(char ) );
strcpy(myinfo[index].studt_name,token);
token = strtok(NULL, ":");
myinfo[index].cources_as_string=(char * ) malloc(200 * sizeof(char ) );
strcpy(myinfo[index].cources_as_string,token);
index++;
}
student_count = index;
fclose(fp);
}
char** return_cource_list(char* cources_string)
{
char *token;
char **cource_list = malloc (sizeof (char *) * 10);
int index = 0;
//course_string is delimited by ",": (eg. Biology,chemistry,maths,music). parse this and add to my char ** variable.
token = strtok(cources_string,",");
cource_list[0]= token;
while (token != NULL)
{
cource_list[index]= token;
token = strtok (NULL, ",");
index++;
}
cource_count = index;
return cource_list;
}
int main()
{
int i,j;
load_file();
for(i=0;i<student_count;i++)
{
printf("============================\n");
printf("NAME: %s >>COURCE_string: %s\n",myinfo[i].studt_name,myinfo[i].cources_as_string);
char ip_list[200];
char** std_cource_list = return_cource_list(myinfo[i].cources_as_string);
for(j=0;j<cource_count;j++)
{
printf("\tCOURCE_list[%d]: %s\n",j,std_cource_list[j]);
//segmentation fault exists here, to copy "std_cource_list[j]" to my struct...(need help here).
strcpy(myinfo[i].cources_as_list[j],std_cource_list[j]);
}
}
}
The problem am facing is to fill the "char **cources_as_list;" member of the struct. Am getting a seg_fault from the inner for loop(iterating on j). Do i miss something in my code?
I fixed it quick so that it doesn't crash and output is correct, it can be better (there are leaks we can fix) but it actually prints your stuff now.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define path "myfile.txt"
typedef struct student_info {
char *studt_name;
char *cources_as_string;
char **cources_as_list;
} std_info;
std_info *myinfo; //a global var that will conatain student info
int student_count = 0, cource_count = 0;
void load_file() {
int i, yu, index = 0;
char *line = NULL, *token = NULL;
size_t len = 0;
FILE *fp;
fp = fopen(path, "r");
if (fp == NULL) {
perror("FILE OPEN ERROR[IN load_file]: ");
return;
}
if ((myinfo = (struct student_info *) malloc(2 * sizeof(*myinfo))) == NULL)//malloc for 2 students
puts("malloc fail");
while (getline(&line, &len, fp) != -1) {
strtok(line, "\n");
char *token;
token = strtok(line, ":");
myinfo[index].studt_name = malloc(200 * sizeof(char));
strcpy(myinfo[index].studt_name, token);
token = strtok(NULL, ":");
myinfo[index].cources_as_string = malloc(200 * sizeof(char));
strcpy(myinfo[index].cources_as_string, token);
index++;
}
student_count = index;
//fclose(fp);
}
char **return_cource_list(char *cources_string) {
char *token;
char **cource_list = malloc(sizeof(char *) * 10);
int index = 0;
//course_string is delimited by ",": (eg. Biology,chemistry,maths,music). parse this and add to my char ** variable.
token = strtok(cources_string, ",");
cource_list[0] = token;
while (token != NULL) {
cource_list[index] = strdup(token);
token = strtok(NULL, ",");
index++;
}
cource_count = index;
return cource_list;
}
/* returns an array of char*, all of which NULL */
char **alloc_argv(unsigned rows) {
char **matrix = malloc(rows * sizeof(char *));
if (!matrix) abort();
for (unsigned row = 0; row < rows; row++) {
matrix[row] = malloc(rows * sizeof(char *));
matrix[row] = "\0";
if (!matrix[row]) abort();
}
return matrix;
}
int main() {
int i, j;
load_file();
for (i = 0; i < student_count; i++) {
printf("============================\n");
printf("NAME: %s >>COURCE_string: %s\n", myinfo[i].studt_name, myinfo[i].cources_as_string);
char ip_list[200];
char **std_cource_list = return_cource_list(myinfo[i].cources_as_string);
for (j = 0; j < cource_count; j++) {
printf("\tCOURCE_list[%d]: %s\n", j, std_cource_list[j]);
//segmentation fault exists here, to copy "std_cource_list[j]" to my struct...(need help here).
myinfo[i].cources_as_list = alloc_argv(100);
myinfo[i].cources_as_list[j] = malloc(sizeof(char **));
strcpy(myinfo[i].cources_as_list[j], std_cource_list[j]);
}
}
}
Output
============================
NAME: Austin Barbra >>COURCE_string: Biology,chemistry,maths,music
COURCE_list[0]: Biology
COURCE_list[1]: chemistry
COURCE_list[2]: maths
COURCE_list[3]: music
============================
NAME: Romio Chandra >>COURCE_string: Mechanics,IT,Geology,music,Astronomy
COURCE_list[0]: Mechanics
COURCE_list[1]: IT
COURCE_list[2]: Geology
COURCE_list[3]: music
COURCE_list[4]: Astronomy
Process finished with exit code 0

Weird seg faults on consecutive calls to the same array

I tried really hard to search for a solution to this but I can't think of good enough keywords.
Currently I'm having troubles grasping the concept behind makeargv and it's usage with triple pointers (I have no idea what ***foo means, it doesn't seem to be as easy of a concept as **foo or *foo). So I made my own:
const char **makeargv(char *string, int *numargs) {
string = string + strspn(string, delims);
char *copy = malloc(strlen(string) + 1);
int i;
strcpy(copy, string);
int numtokens;
if (strtok(copy, delims) != NULL) {
for (numtokens = 1; strtok(NULL, delims) != NULL; numtokens++) {}
}
strcpy(copy, string);
const char *results[numtokens+1];
results[0] = strtok(copy, delims);
for (i = 1; i < numtokens; i++) {
results[i] = strtok(NULL, delims);
}
results[numtokens+1] = NULL;
*numargs = numtokens;
return results;
}
Here's the part at where it breaks:
void parse_file(char* filename) {
char* line = malloc(160*sizeof(char));
FILE* fp = file_open(filename);
int i = 0;
int numargs = 0;
int *pointer = &numargs;
while((line = file_getline(line, fp)) != NULL) {
if (strlen(line) == 1){
continue;
}
const char **args = makeargv(line, pointer);
printf("%s\n", args[0]);
printf("%s\n", args[1]);
/* This prints out args[0], but then args[1] causes a seg fault. Even if I replace
the args[1] with another args[0] it still causes a seg fault */
}
fclose(fp);
free(line);
}
I have a working array of strings. However when I try to print out the strings in the array, I can only print 1 of my choice and then it seg faults for any subsequent calls. lets pretend my array of strings is argv[3] = {"Yes", "no", "maybe"}, if i call argv[0], it will let me call "Yes", but any other calls (even if i call argv[0] again) do not work and cause a segfault. I can call any of the elements in the array, but once i call one the rest cease to work causing segfaults.
Help please? D: This is in C.
const char *results[numtokens+1];
This array "results" is a local variable, it is only available inside of "makeargv".
You'd better use malloc:
results = malloc(numtokens+1)
And I believe there is memory leak in your code.
You will not be able to free the memory for "char *copy"
char *copy = malloc(strlen(string) + 1);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **makeargv(char *string, int *numargs) {
static const char *delims = " \t\n";
string = string + strspn(string, delims);
char *copy = malloc(strlen(string) + 1), *p = copy;
strcpy(copy, string);
int numtokens;
for (numtokens = 0; strtok(p, delims); ++numtokens, p = NULL);
char **results = malloc(sizeof(char*)*(numtokens+1));
strcpy(copy, string);
int i;
p = copy;
for (i = 0; i < numtokens; ++i, p = NULL)
results[i] = strtok(p, delims);
results[i] = NULL;
*numargs = numtokens;
return results;
}
FILE *file_open(char *filename){
FILE *fp = fopen(filename, "r");
if(!fp){
perror("file_open");
exit(1);
}
return fp;
}
void parse_file(char* filename) {
char* line = malloc(160*sizeof(char));
FILE* fp = file_open(filename);
int i = 0, numargs = 0;
while(fgets(line, 160, fp)){
if (*line == '\n')
continue;
char **args = makeargv(line, &numargs);
for(i = 0;i<numargs;++i)
printf("%s\n", args[i]);
printf("\n");
if(args[0])
free(args[0]);
free(args);
}
fclose(fp);
free(line);
}
int main(int argc, char *argv[]){
parse_file(argv[1]);
return 0;
}

Resources