getting a "free(): invalid pointer" in c - c

i am new at writing in c,
my program is for parsing a txt file and save the first word in a struct named File.
for exmple:
for a txt file containing:
file1: file2,file3
file66: file7
i would like to save file1 and file2 in a struct
when
file1->name=file1
fiel1->relation=[file2,file3]
but this just for a bit explantion of the program.
the problem is:
because i dont know the size of the array of chars that would represent the name i were trying to use dynamic memory using malloc and free
in the process i am using strtok for the parsing part
the problem start in the 4 last lines (marked in a comment)
and i keep getting the error "free(): invalid pointer: 0x00007ffe6accfdd0 ***"
(i looked in the website for answers but i because the lack of understanding in pointer it was hard for me to get the idea of the problem).
someone can explain me why?
thank you from advance
typedef struct File
{
char *name;
int *relation;
}File;
char *error = BAD_FILE_MSG;
char buffer[MAX_LEN_SIZE];//the file buffer
if (argc != RIGHT_NUM_OF_PARAM) {
fprintf(stderr, UNVALID_PARAMETER_MSG);
return BAD_RET_VAL;
}
char *fileName = argv[1];
FILE *fp = fopen(argv[1], "r"); /* "r" = open for reading */
if (fp == NULL)
{
fprintf(stderr, "%s %s", error, fileName);
return BAD_RET_VAL;
}
if (ferror(fp) != 0)
{
fprintf(stderr, "%s %s", error, fileName);
return BAD_RET_VAL;
}
//int line = 0;//todo magic
while (fgets (buffer, sizeof(buffer), fp))
{
/**
* saving all the line in a char[]
*/
//give memory to an array in file
char *token;
token = strtok (buffer, SIGN_FOR_SEPARATE);
int marker = 0;//todo fix
//creating a struct of a file
File* fileStruct = (File*)malloc(sizeof(File));
//creating a dynamic array of ints for relation
fileStruct->relation = (int *)malloc(100 * sizeof(int));//todo free your mind
char file[100];
while (token != NULL)
{
if (marker == 0)
{
char* pointer = fileStruct->name;
size_t size = strlen(token);
//creating a dynamic array of chars for name
fileStruct->name = (char *)malloc(size + 1);
fileStruct->name = token;//**getting the error**
free(pointer);
marker++;
}

I'm just going to focus on what is causing your error (I didn't read most of your code).
Pointers are one of the concepts in C that take a long time to learn, and you have a long way to go.
A pointer is just an address in memory, nothing else. You can think of *pointer as being a function call that says, "take the number stored in pointer, go out to memory, and return the value that you find at the address corresponding to that number".
When you say:
char* pointer = fileStruct->name;
You aren't connecting those two variables in any way. It would be like saying:
int foo = 3;
int bar = foo;
For now they have the same value, but if you change foo, bar doesn't change.
In your code, you aren't actually using pointer anywhere, so you can just gt rid of it and call free(fileStruct->name) when you are done using it.
That being said, you need more practice/reading/learning about how pointers work. If you are just starting to program in general, you might want to avoid pointers all together until you are are comfortable with the basics.

Related

Why does my C program crash when i add any statement to the main function?

I'm reasonably new to C - I've made a program that reads a text file and through several functions processes the text by using malloc() and realloc() and formats an output. At the moment I only have the following in my main():
1. initializing the structs
line_arr.max_size = 0;
line_arr.num_lines = 0;
line_arr.line = NULL;
Word_Array word_arr;
word_arr.max_size_ = 0;
word_arr.num_words = 0;
word_arr.word = NULL;
Word_Array ex_words;
ex_words.max_size_ = 0;
ex_words.num_words = 0;
ex_words.word = NULL;
Line_Array.line and Word_Array.word are both pointers to structs Line and Word, respectively. Line and Word are structs that hold a char array and an int that keeps track of what line number the line is or the word occurs in.
2. calling the functions that process the input text files
get_lines(&line_arr, argv[1]);
get_words(&line_arr, &word_arr);
sort_keywords(&word_arr);
All of my functions return void.
All the output and formatting occurs within the functions and any space I have malloc'd I have subsequently freed without any error. The program produces the desired output, however if I add any statement to the main() even a print statement, I get a bus10 error or a segmentation fault 11 error.
I have tried gdb but I haven't used it before, and it seems as though gdb hangs and freezes when I try to run the program anyway.
I'm wondering if anyone knows why this is the case? / is there some fundamental logic I'm not understanding about C or malloc()?
Thanks for your expertise!
edit
structs:
typedef struct Line Line;
struct Line{
char line[MAX_LINE_LEN];
};
typedef struct Word{
char word[MAX_WORD_LEN];
int line_number;
}Word;
typedef struct Word_Array{
//will point to the base in memory where the list of words begins.
Word *word;
int max_size_;
int num_words;
}Word_Array;
typedef struct Line_Array{
//line is a variable that stores an address of a line object.
Line *line;
int max_size;
int num_lines;
}Line_Array;
get_lines():
void get_lines(Line_Array *la, char const *filename){
Line *line_ptr;
char *buffer;
size_t buffer_len;
FILE *fp = fopen(filename, "r");
if(fp == NULL){
printf("Can't read file. \n");
exit(1);
}
while (getline(&buffer, &buffer_len, fp) > 0) {
buffer[strlen(buffer)-1] = '\0';
if (la->line == NULL) {
la->line = (Line *) malloc(sizeof(Line));
if (la->line == NULL) {
exit(1);
}
la->max_size = 1;
la->num_lines = 0;
}
else if (la->num_lines >= la->max_size) {
line_ptr = (Line *) realloc(la->line, (2*la->max_size) * sizeof(Line));
if (line_ptr == NULL) {
exit(1);
}
la->max_size *= 2;
la->line = line_ptr;
}
strncpy(la->line[la->num_lines].line, buffer, MAX_LINE_LEN);
la->num_lines++;
}
fclose(fp);
}
I haven't freed the memory in this method since I make use of it later, but even when other functions aren't being run the same problem exists where if I add something to the main before or after calling get_lines, I receive bus 10 error as my only output. However if i only call get_lines() and other functions the program produces the right output.
A least one problem:
Variables need to be initialized before getline() usage. #Weather Vane
//char *buffer;
//size_t buffer_len;
char *buffer = NULL;
size_t buffer_len = 0;
Notes:
After the while (getline(... , code should free with free(buffer);
strncpy(la->line[la->num_lines].line, buffer, MAX_LINE_LEN); does not insure la->line[la->num_lines].line is a string. Why is strncpy insecure?

Using realloc to dynamically grow array of structs causes heap corruption

I'm trying to read structured data from a txt file and store it into a struct. Since I don't know how many entries this file will have, I have to dynamically grow an array of structs. I've tried doing that with realloc, as per the following code sample:
#define BUFFER 200
#define ENTRY_MAX 10 // default number of entries
typedef struct data_storage {
// store data in this struct
}data_storage;
int main() {
FILE *fp;
data_storage *data;
char arr[10*BUFFER];
char *token; // some data
const char s[2] = ";"; // this is the data separator in txt file
char *token_array[ENTRY_MAX];
int i = 0; // iterator
int number_of_entries = 1; // starts with at least one entry
fp = fopen("sample_file.txt", "r");
if(fp == NULL) {
printf("Impossible to open file \n");
return 1;
}
fgets(arr, 1000, fp); // gets a chunk of data from file
token = strtok(arr, s);
data = malloc(number_of_entries*sizeof(data_storage));
while( token != NULL) {
token = strtok(NULL, s);
token_array[i] = token;
i++;
if(i >= ENTRY_MAX){
/*
DO STUFF: uses strcpy to copy entries from token_array to data
*/
number_of_entries++; // increments number of entries
data = realloc(data, number_of_entries*sizeof(data_storage));
i = 0; // proceeds to read next entry
}
}
fclose(fp);
return 0;
}
Basically, I'm trying to use strtok to read a default number of fields, and when the number of tokens reaches ENTRY_MAX I know that I've read an entire entry and can allocate memory for one more struct.
But I'm getting a realloc(): invalid next size: error, which looks like heap corruption.
Per the documentation of realloc, if it fails it returns NULL. As a result data = realloc(data,...) can cause a corruption of the pointer should the function fail. This could lead to ask sorts of issues in the posted code

Creating a File to array function

Currently I have the argc, argv and temp pieces placed in to be passed, and when I compile it returns no errors, but when I call the function later in the program and pass it a char array. It returns a stack dump. From what I have learned so far arrays cannot be passed back from a function and that is why I have passed the pointers.
int In2File(int argc, char *argv[], char *temp[] ){
if (argc == 2) { //open file
FILE *user_file;
user_file = fopen(argv[1], "r");
if (user_file == NULL) {
printf("No data was found.\nEnd(Error 1)");
exit(2);
}
else {
int g = 0;//temp counter to load
char c = 0;
while ((c = fgetc(user_file)) != EOF && g <= tmplng - 1) { //Used Fgetc instead of fgets because Fgetc allows me to read
*temp[g] = c; //until the end of the file and read each character. Even if there is an \n character.
g++; // The second g < tmplng-1 is used to make sure that the \0 can be placed into the array.
}
printf("%s\n", temp);
fclose(user_file);//Closed the txt file that was loaded by user in args(1)
printf("\nFile Loaded.\n");
}
}
else if (argc > 2) { // Will exit if arguments are greater than 2.
printf("Format: %s 'filename'", argv[0]);
exit(1);
}
else {
printf("File not provided. Enter information:\n");//If the user doesnt provide a file allow manual input.
fgets(*temp, tmplng, stdin);
}
}
In2File(argc,argv,temp);
Anyone have an idea as to where I went wrong with this function? I read a few similar posts but they were for C++ and Python. Which I havent learned C++ as yet and python is different to this beast called C.
Edit:
const int tmplng = 1000; //The only variables needed
char temp[tmplng]; //
char temp2[tmplng]; //
printf("Starting....\n"); //Used for testing debugging.
The third parameter to the function doesn't match what the function is expecting. You're passing in a char [] (which decays to a char *), while the function expects char *[] (equivalently char ** as a function parameter).
The definition of the third parameter doesn't match how you intend to use it, which is as a character array.
Get rid of the extra level of indirection on the parameter, and adjust the function accordingly.
int In2File(int argc, char *argv[], char temp[] ){
...
while ((c = fgetc(user_file)) != EOF && g <= tmplng - 1) {
temp[g] = c;
g++;
}
This declaration of temp:
char temp[tmplng];
... does not go with this call ...
In2File(argc,argv,temp);
... to this function ...
int In2File(int argc, char *argv[], char *temp[] );
The function expects its third argument to be a pointer to a pointer to char *, but what it receives is a pointer to char. When it then tries to assign the character read ...
*temp[g] = c;
That attempts to interpret the gth element of temp (itself interpreted as a char **) as a char *, to dereference that pointer, and to assign c to that location. That is highly unlikely to be a valid memory access.
It looks like you want to declare the third argument of In2File as either char *temp or char temp[], which are equivalent, and to write to it as temp[g] = c.
ALSO, as an aside, note that your
printf("%s\n", temp);
is problematic because you do not ensure that temp is null-terminated. And inasmuch as you support reading up to the very last byte, you don't have room to terminate it.
As numerous folks are pointing out in the comments, your code would be much easier to understand if you employed "early exit" for your error conditions.
It would also be a better separation of concerns to have main deal with the program arguments and let In2File just deal with a file pointer.
int main( int argc, char *argv[] ) {
FILE *fp;
if( argc == 2 ) {
fp = fopen(argv[1], "r");
if ( fp == NULL ) {
fprintf(stderr, "Couldn't open %s: %s", argv[1], strerror(errno));
exit(2);
}
}
else if( argc > 2 ) {
fprintf(stderr, "Usage: %s <optional filename>", argv[0]);
exit(1);
}
else {
fp = stdin;
}
char *lines = In2File(fp);
printf("%s\n", lines);
free(lines);
}
Note that stdin is a file pointer just like anything you opened with fopen. I've also used strerror and errno to provide the reason the file didn't open.
Now In2File just takes a file pointer. Also note that I have it returning the content, not passing in a preallocated array. This is because when reading from input you never know how much input you're going to get. You either must stop reading before you run out of space, or allocate more memory. You can't reallocate stack memory, so it's best to let In2File control allocating memory. It also avoids having to pass around a global variable.
Once that's done, In2File becomes much simpler.
static char *In2File( FILE *fp ){
size_t read_size = 1024;
/* Don't forget space for null */
char *content = calloc( read_size + 1, sizeof(char) );
fread( content, sizeof(char), read_size, fp );
return content;
}
Rather than step through a character at a time, I've used fread to read a block from the file not larger than the amount I've allocated. Memory reallocation is a topic for another time.

Storing line by line from text file into char array using char pointer

Hello I writing a program to execute commands from the text file. The code below is used to store line by line into char array first.
So I expect it to do something like
args[0]= The first line of text file
args[1]= The second line of text file
... and so on
In my code, all of the arrays would be covered by the last array. And I can't figure out why.
Can anyone help me fix this and tell me why my code does that. Also I need to keep char *args[]. cos I would use it with execvp() later.
int main(int argc, const char * av[]) {
FILE *fp;
fp = fopen(av[1],"r");
int n_lines=0;
char in[100],*args[16];
int size=sizeof(in);
while(fgets(in, size, fp)!=NULL){
args[n_lines] = in;
printf("Args[0] is %s\n",args[0]);
n_lines++;
}
printf("Now Args[0] is %s\n",args[0]);
}
Output
zacks-MacBook-Pro:prac2 zack$ ./a.out test
Args[0] is ./addone
Args[0] is ./add
Now Args[0] is ./add
int n_lines=0;
char in[100],*args[16];
int size=sizeof(in);
while(fgets(in, size, fp)!=NULL){
args[n_lines] = in;
printf("Args[0] is %s\n",args[0]);
n_lines++;
}
The value of in is overwritten on each iteration, you need to reserve space (using malloc->strcpy or strdup if available):
char in[100], *args[16];
while (fgets(in, sizeof in, fp) != NULL) {
args[n_lines] = strdup(in);
...
n_lines++;
}
Or use a 2D array (an adjust of sizeof is required in fgets):
char in[16][100];
while (fgets(in[n_lines], sizeof in[0], fp) != NULL) {
...
n_lines++;
}
And as pointed out by #MichaelWalz in comments: you'll run into problems if your file has more then 16 lines.
Change to
while (fgets(in[n_lines], sizeof in[0], fp) != NULL) {
...
if (++n_lines == (sizeof in / sizeof in[0])) break;
}

Getting the error message "assignment makes pointer from integer without a cast" while trying to write a parsing program

I'm trying to write a parsing program that will read the file /proc/stat and store its various tokens in arrays. This is the progress I have made so far. my problem comes with the line
s = strtok(str, " ");
With this line I get the error message:
ass2.c:62:15: warning: assignment makes pointer from integer without a cast [enabled by default]
s = strtok(string, " ");
I'm not sure how to solve this issue. I'm just about a complete beginner with C so not familiar with the feedback terms and so I'm struggling to rectify this issue. Below I have pasted the entire programs code so far.
//standard input/output file to help with io operations
#include<stdio.h>
//standard library files to help with exit and other standard functions
#include<stdlib.h>
//header file for usleep function
#include <unistd.h>
int main()
{
//FILE pointer will need to be declared initially, in this example the name is fp
FILE *fp;
//A character pointer that will store each line within the file; you will need to parse this line to extract useful information
char *str = NULL;
//size_t defined within C is a unsigned integer; you may need this for getline(..) function from stdio.h to allocate buffer dynamically
size_t len = 0;
//ssize_t is used to represent the sizes of blocks that can be read or written in a single operation through getline(..). It is similar to size_t, but must be a signed type.
ssize_t read;
int cpu_line1[5];
int cpu_line2[5];
int cpu_line3[5];
int cpu_line4[5];
int cpu_line5[5];
int page_line[3];
int swap_line[3];
int intr_line[2];
int ctxt_line[2];
int btime_line[2];
//a variable declared to keep track of the number of times we read back the file
unsigned int sample_count = 0;
//opening the file in read mode; this file must be closed after you are done through fclose(..); note that explicit location of the file to ensure file can be found
fp = fopen("/proc/stat", "r");
//checking if the file opening was successful; if not we do not want to proceed further and exit with failure code right away
if(fp == NULL)
{
exit(EXIT_FAILURE);
}
int i = 0;
char **string = NULL; //declaration of string
string = (char**)malloc(10*sizeof(char*)); //assign space for 10 pointers to array
for (i=0; i<10; i++) //allocate 50 bytes to each string in the array
{
string[i] = (char*)malloc(50*sizeof(char));
}
//a loop that will read one line in the file at a time; str will read the line; len will store the length of the file
while(sample_count < 1)
{
printf("\e[1;1H\e[2J"); //this line will make sure you have cleared the previous screen using C's powerful format specifiers
printf("----------------------------------------------------------------\n");//used for presentation
printf("Sample: %u\n", sample_count); //showing the sample count
while ((read = getline(&str, &len, fp)) != -1)
{
printf("Retrieved line: \n%sof length: %zu, allocated buffer: %u :\n", str, read, (unsigned int) len);
//You will then need to extract the useful information, including the name and the statistics
char *s = NULL;
s = strtok(str, " ");
sprintf(string[i], s);
printf("Test: %s", string[0]);
}
if (i=0)
{
cpu_line1[0] = atoi(strtok(NULL, " "));
cpu_line1[1] = atoi(strtok(NULL, " "));
cpu_line1[2] = atoi(strtok(NULL, " "));
}
printf("----------------------------------------------------------------\n"); //used for presentation
usleep(500000);//this will ensure time delay
rewind(fp);//rewind the file pointer to start reading from the beginning
sample_count++;//update the sample count
}
//once you are done, you should free the pointers to make your program memory efficient
free(str);
//once you are done, you should also close all file pointers to make your program memory efficient
fclose(fp);
return 0;
}
Since you did not #include the header file in which strtok is declared, the compiler assumes that the return type of the function is int. Hence, the warning.
Add
#include <string.h>
to fix the problem.

Resources