Why do I get 0 bytes after a block of size 7 alloc'd error when I am still leaving space for '\0'?
I tried allocating and reallocating 7 bytes and kept the size variable going up by 5 so that there would always be at least 2 bytes left at the end when I add the null terminator, but I am still getting the valgrind error:
Invalid write of size 1:
0 bytes after a block of size 7 alloc'd
whenever I read or write to token, for example I get it on this line:
token[i] = read;
void parse_file(char file[]) {
char read = 0;
int size = 5;
char *token = NULL;
int i = 0;
FILE *fp = NULL;
token = malloc(7 * sizeof(char));
fp = fopen(file, "r");
if(fp == NULL) {
fprintf(stderr, "%s: No such file or directory\n", file);
free(token);
fclose(fp);
return;
}
read = fgetc(fp);
while(read != EOF) {
if(i == size) {
token = realloc(token, 7 * sizeof(char));
size += 5;
}
if(isalpha(read)) {
read = (char) tolower(read);
token[i] = read;
}
else {
if(isalpha(token[0])) {
token[i] = '\0';
put(token);
}
else {
free(token);
}
token = calloc(7,sizeof(char));
size = 5;
i = 0;
read = fgetc(fp);
continue;
}
read = fgetc(fp);
i++;
}
free(token);
fclose(fp);
}
the following proposed code:
cleanly compiles
eliminates unnecessary code/logic
performs the desired functionality
properly checks for errors
incorporates the comments to the OPs question
incorporates the comments to this answer
and now the proposed code: (EDITED)
#include <stdlib.h> // exit(), EXIT_FAILURE, realloc(), free()
#include <stdio.h> // FILE, fprintf(), fopen(), fgetc(), perror()
#include <ctype.h> // isalpha(), tolower()
#include <errno.h> // errno
#include <string.h> // strerror()
// prototypes
void parse_file(char fileName[]);
void parse_file(char fileName[])
{
int byteRead = 0;
size_t size = 0;
char *token = NULL;
size_t i = 0;
FILE *fp = NULL;
fp = fopen(fileName, "r");
if( !fp )
{
fprintf(stderr, "Can't open %s: %s\n", fileName, strerror(errno));
exit( EXIT_FAILURE );
}
while( (byteRead = fgetc(fp) ) != EOF )
{
char *temp = NULL;
if(i >= size)
{
temp = realloc(token, 7 + size );
if( !temp )
{
perror( "realloc failed" );
free( token );
fclose( fp );
exit( EXIT_FAILURE );
}
// implied else, realloc successful
size += 7;
token = temp;
}
if( isalpha(byteRead) )
{
byteRead = tolower(byteRead);
token[i] = (char)byteRead;
i++;
}
else if( i )
{
token[i] = '\0';
puts(token);
free( token );
i = 0;
size = 0;
}
}
free(token);
fclose(fp);
}
Related
I've to read character by character from a file and put each line in a String.
The problem is that i don't know the size of each line so eventually I've to reallocate the memory. So If I try a reallocation my program return error. Am I doing something wrong?
FILE * file = fopen(input,"r");
if(file != NULL){
char temp;
char * line;
line = (char *) malloc(sizeof(char) * 10);
int i = 0;
while((temp = fgetc(file)) != EOF){
if(temp == '\n'){
i = 0;
}
else{
if(i > strlen(line) - 2){
line = (char *) realloc(line,sizeof(line) * 10);
}
line[i] = (char) temp;
i++;
}
}
free(line);
fclose(file);
}
else{
}
the following proposed code:
cleanly compiles
performs the desired functionality
properly checks for errors
outputs user error messages to stderr
outputs the text reason the system thinks an error occurred to stderr
documents why each header file is included
shows an example of how to handle the case where the user failed to enter a command line parameter (in this case a input file name)
makes use of size_t rather than int when passing parameters to malloc() and realloc()
and now, the proposed code:
#include <stdio.h> // fopen(), perror(), fclose() fprintf()
#include <stdlib.h> // exit(), EXIT_FAILURE, malloc(), realloc(). free()
int main( int argc, char *argv[] )
{
if( argc != 2 )
{
fprintf( stderr, "USAGE: %s <fileName>\n", argv[0] );
exit( EXIT_FAILURE );
}
FILE * file = fopen( argv[1], "r" );
if( !file )
{
perror( "fopen failed" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
int ch;
char * line = malloc( 10 );
if( !line )
{
perror( "malloc failed" );
fclose( file ); // cleanup
exit( EXIT_FAILURE );
}
// implied else, malloc successful
size_t lineLen = 10;
size_t i = 0;
while( (ch = fgetc(file)) != EOF )
{
if( ch == '\n' )
{
line[i] = '\0';
// do something with contents of line
i = 0;
}
else
{
if(i >= lineLen )
{
lineLen *= 2;
char * temp = realloc( line, lineLen );
if( !temp )
{
perror( "realloc failed" );
// cleanup
fclose( file );
free( line );
exit( EXIT_FAILURE );
}
line = temp;
}
line[i] = (char)ch;
i++;
}
}
free(line);
fclose(file);
}
I want to sort strings from file; this code compiles well, but it stops working in line 29, when I do words_array[i] = strdup(line);.
From debugger I have "program received signal sigsegv segmentation fault"
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int comparator ( const void * elem1, const void * elem2 )
{
return strcmp( *(const char**) elem1, *(const char**) elem2);
}
int main()
{
char filename[]="dane.txt";
FILE* fp;
char* line = NULL;
size_t len = 0;
char** words_array = NULL;
int i = 0,j; // number of elements
// read list from file
if( ( fp = fopen(filename, "r") ) == NULL ) {
fprintf(stderr, "Cannot open source file %s!\n", filename);
exit(1);
}
for(; fgets(line, len, fp) != NULL; ++i) {
// put word in array
words_array = realloc(words_array, sizeof(char*) * (i + 1) );
words_array[i] = strdup(line);
}
fclose(fp);
free(line);
// sort it
qsort(words_array, i, sizeof(char*), comparator);
if( ( fp = fopen(filename, "a+") ) == NULL ) {
fprintf(stderr, "Cannot open source file %s!\n", filename);
exit(1);
}
// write to file and free dynamically allocated memory
for(j = 0; j < i; ++j) {
fprintf(fp, "%s", words_array[j]);
free(words_array[j]);
}
free(words_array);
fclose(fp);
return 0;
}
You never allocated space for line to point to.
I have a csv file having values
1,A,X
2,B,Y
3,C,Z
I have to read the CSV file line by line and keep it in a Structure array.
The values are going fine each time in the for loop. But at the end when I am printing the Array, only the last value is being printed.
Somebody please tell me where am I doing the logical error?
struct proc
{
char *x;
char *y;
};
void main()
{
fflush(stdin);
fflush(stdout);
const char s[2] = ",";
char *token;
int rows=0,i,tokenVal=0,rowCount=0;
FILE *fpCount = fopen("data.csv","r");
if(fpCount != NULL)
{
char lineCount[20];
while(fgets(lineCount, sizeof lineCount, fpCount))
rows++;
}
struct proc *pi[rows];
for(i=0;i<rows;i++)
pi[i] = (struct proc*) malloc(sizeof(struct proc));
FILE *fp = fopen("data.csv", "r");
if(fp != NULL)
{
char line[20];
while(fgets(line, sizeof line, fp) != NULL)
{
printf("Start rowCount = %d\t",rowCount);
token = strtok(line, s);
while(token!=NULL)
{
if(tokenVal==0)
{
pi[rowCount]->Id =token;
}
if(tokenVal==1)
{
pi[rowCount]->act = token;
}
printf("\n");
tokenVal++;
token = strtok(NULL,s);
}
tokenVal = 0;
printf("end rowCount = %d\t",rowCount);
rowCount++;
}
fclose(fp);
} else {
perror("data.csv");
}
printf("total %d",rowCount);
int k=0;
for(k=0;k<rowCount;k++)
{
printf(" %d = %s----%s",k,pi[k]->Id,pi[k]->act);
}
}
Diagnosis
The fundamental problem you face is that you are saving pointers to the variable line in your structures, but each new line overwrites what was previously in line, so at the end, only data from the last line is present. It is fortuitous that your lines of data are all the same 'shape'; if the fields were of different lengths, you'd have more interesting, but equally erroneous, results.
Consequently, you need to save a copy of each field, not simply a pointer to the field. The simple way to do that is with POSIX function strdup(). If you don't have the function, you can create it:
char *strdup(const char *str)
{
size_t len = strlen(str) + 1;
char *rv = malloc(len);
if (rv != 0)
memmove(rv, str, len); // or memcpy
return rv;
}
Your code doesn't compile; your data structure has elements x and y but your code uses elements Id and act. You use a VLA of pointers to your struct proc, but it would be sensible to allocate an array of the structure, either as a VLA or via malloc() et al. You should check memory allocations — there isn't a way to check VLAs, though (one reason to use dynamic allocation instead). You could rewind the file instead of reopening it. (It's a good idea to use a variable to hold the file name, even if you only open it once; it makes error reporting better. Also, errors should stop the program, in general, though you did use perror() if the reopen operation failed — but not if the open failed.) You don't need two arrays into which to read the lines. It's a good idea to use far longer buffers for input lines. You should free dynamically allocated memory. Also, see What should main() return in C and C++?; the answer is int and not void (unless perhaps you are on Windows).
Here are three variants of your code, with various aspects of the issues outlined above more or less fixed.
VLA of pointers
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct proc
{
char *x;
char *y;
};
int main(void)
{
const char datafile[] = "data.csv";
const char csv_delim[] = ",\n";
int rows = 0, rowCount = 0;
FILE *fpCount = fopen(datafile, "r");
if (fpCount == NULL)
{
fprintf(stderr, "Failed to open '%s' for reading\n", datafile);
exit(EXIT_FAILURE);
}
char lineCount[2000];
while (fgets(lineCount, sizeof(lineCount), fpCount))
rows++;
fclose(fpCount);
printf("Read %d rows from '%s'\n", rows, datafile);
struct proc *pi[rows];
for (int i = 0; i < rows; i++)
pi[i] = (struct proc *)malloc(sizeof(struct proc));
FILE *fp = fopen(datafile, "r");
if (fp == NULL)
{
fprintf(stderr, "Failed to reopen '%s' for reading\n", datafile);
exit(EXIT_FAILURE);
}
char line[2000];
while (fgets(line, sizeof(line), fp) != NULL)
{
printf("Start rowCount = %d\t", rowCount);
int tokenVal = 0;
char *token = strtok(line, csv_delim);
while (token != NULL)
{
if (tokenVal == 0)
{
pi[rowCount]->x = strdup(token);
}
else if (tokenVal == 1)
{
pi[rowCount]->y = strdup(token);
}
printf("[%s]", token);
tokenVal++;
token = strtok(NULL, csv_delim);
}
printf("\tend rowCount = %d\n", rowCount);
rowCount++;
}
fclose(fp);
/* Data validation */
printf("total %d\n", rowCount);
for (int k = 0; k < rowCount; k++)
{
printf("%d = [%s]----[%s]\n", k, pi[k]->x, pi[k]->y);
}
/* Release allocated memory */
for (int k = 0; k < rowCount; k++)
{
free(pi[k]->x);
free(pi[k]->y);
free(pi[k]);
}
return 0;
}
VLA of structures
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct proc
{
char *x;
char *y;
};
int main(void)
{
const char datafile[] = "data.csv";
const char csv_delim[] = ",\n";
int rows = 0, rowCount = 0;
FILE *fpCount = fopen(datafile, "r");
if (fpCount == NULL)
{
fprintf(stderr, "Failed to open '%s' for reading\n", datafile);
exit(EXIT_FAILURE);
}
char lineCount[2000];
while (fgets(lineCount, sizeof(lineCount), fpCount))
rows++;
fclose(fpCount);
printf("Read %d rows from '%s'\n", rows, datafile);
struct proc pi[rows];
FILE *fp = fopen(datafile, "r");
if (fp == NULL)
{
fprintf(stderr, "Failed to reopen '%s' for reading\n", datafile);
exit(EXIT_FAILURE);
}
char line[2000];
while (fgets(line, sizeof(line), fp) != NULL)
{
printf("Start rowCount = %d\t", rowCount);
int tokenVal = 0;
char *token = strtok(line, csv_delim);
while (token != NULL)
{
if (tokenVal == 0)
{
pi[rowCount].x = strdup(token);
}
else if (tokenVal == 1)
{
pi[rowCount].y = strdup(token);
}
printf("[%s]", token);
tokenVal++;
token = strtok(NULL, csv_delim);
}
printf("\tend rowCount = %d\n", rowCount);
rowCount++;
}
fclose(fp);
/* Data validation */
printf("total %d\n", rowCount);
for (int k = 0; k < rowCount; k++)
{
printf("%d = [%s]----[%s]\n", k, pi[k].x, pi[k].y);
}
/* Release allocated memory */
for (int k = 0; k < rowCount; k++)
{
free(pi[k].x);
free(pi[k].y);
}
return 0;
}
Dynamic array of structures
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct proc
{
char *x;
char *y;
};
int main(void)
{
const char datafile[] = "data.csv";
const char csv_delim[] = ",\n";
int num_rows = 0, rowCount = 0;
FILE *fp = fopen(datafile, "r");
if (fp == NULL)
{
fprintf(stderr, "Failed to open '%s' for reading\n", datafile);
exit(EXIT_FAILURE);
}
char line[2000];
while (fgets(line, sizeof(line), fp))
num_rows++;
rewind(fp);
printf("Read %d rows from '%s'\n", num_rows, datafile);
struct proc *pi = calloc(num_rows, sizeof(*pi));
if (pi == 0)
{
fprintf(stderr, "Failed to allocate %zu bytes of memory\n", num_rows * sizeof(*pi));
exit(EXIT_FAILURE);
}
while (fgets(line, sizeof(line), fp) != NULL)
{
printf("Start rowCount = %d\t", rowCount);
int tokenVal = 0;
char *token = strtok(line, csv_delim);
while (token != NULL)
{
if (tokenVal == 0)
{
pi[rowCount].x = strdup(token);
// null check
}
else if (tokenVal == 1)
{
pi[rowCount].y = strdup(token);
// null check
}
printf("[%s]", token);
tokenVal++;
token = strtok(NULL, csv_delim);
}
printf("\tend rowCount = %d\n", rowCount);
rowCount++;
}
fclose(fp);
/* Data validation */
printf("total %d\n", rowCount);
for (int k = 0; k < rowCount; k++)
{
printf("%d = [%s]----[%s]\n", k, pi[k].x, pi[k].y);
}
/* Release allocated memory */
for (int k = 0; k < rowCount; k++)
{
free(pi[k].x);
free(pi[k].y);
}
free(pi);
return 0;
}
Given a data file:
1,A,X
2,B,Y
3,C,Z
3192-2146-9913,Abelone,Zoophyte
all three programs produce the same output:
Read 4 rows from 'data.csv'
Start rowCount = 0 [1][A][X] end rowCount = 0
Start rowCount = 1 [2][B][Y] end rowCount = 1
Start rowCount = 2 [3][C][Z] end rowCount = 2
Start rowCount = 3 [3192-2146-9913][Abelone][Zoophyte] end rowCount = 3
total 4
0 = [1]----[A]
1 = [2]----[B]
2 = [3]----[C]
3 = [3192-2146-9913]----[Abelone]
In the printf(" %d = %s----%s----%s",k,pi[k]->Id,pi[k]->act);
There are four data
%d
%s
%s
%s
but you set only three
k
pi[k]->Id
pi[k]->act
I'm trying to build a gym program for a project in college.
We're doing it in C in a Linux environment.
I do not have problems reading from the file, but when I try to update the file, if I print to file with '\n' at the end, it puts double enters between line. And if I don't, it puts all the data in one line.
What should I do?
i.e. I've added an example of a function that reads from the file and one that updates it.
Employees** Init_Gym_emp(Employees** emp, int* num) {
FILE* f = fopen("Gym Employees.txt", "r");
if (f == NULL) {
printf("Failed opening the file. Exiting!\n");
exit(1);
}
char c = '\0';
while (fscanf(f, "%c", &c) == 1) {
if (c == '\n') num[0]++;
}
if (num[0] > 0) num[0]++;
fseek(f, 0, SEEK_SET);
Employees* tmp = (Employees*)malloc(sizeof(Employees));
if (tmp == NULL) {
printf("Memory allocation failed\n");
exit(1);
}
emp = (Employees**)malloc(sizeof(Employees*)*(num[0]));
if (emp == NULL) {
printf("Memory allocation failed\n");
exit(1);
}
int i = 0;
tmp->first_name = (char*)malloc(sizeof(char)* 20);
tmp->last_name = (char*)malloc(sizeof(char)* 20);
tmp->user_name = (char*)malloc(sizeof(char)* 20);
tmp->password = (char*)malloc(sizeof(char)* 20);
tmp->user_type = (char*)malloc(sizeof(char)* 20);
while (fscanf(f, "%20[^#]%*c%20[^#]%*c%ld%*c%20[^#]%*c%10[^#]%*c%20[^#]%*2c", tmp->first_name, tmp->last_name, &tmp->id, tmp->user_name, tmp->password, tmp->user_type) == 6) {
emp[i] = (Employees*)malloc(sizeof(Employees));
if (emp[i] == NULL) {
printf("Memory allocation failed\n");
exit(1);
}
emp[i]->first_name = (char*)malloc(sizeof(char)* (strlen(tmp->first_name) + 1));
emp[i]->last_name = (char*)malloc(sizeof(char)* (strlen(tmp->last_name) + 1));
emp[i]->user_name = (char*)malloc(sizeof(char)* (strlen(tmp->user_name) + 1));
emp[i]->password = (char*)malloc(sizeof(char)* (strlen(tmp->password) + 1));
emp[i]->user_type = (char*)malloc(sizeof(char)* (strlen(tmp->user_type) + 1));
strcpy(emp[i]->first_name, tmp->first_name);
strcpy(emp[i]->last_name, tmp->last_name);
strcpy(emp[i]->user_name, tmp->user_name);
strcpy(emp[i]->password, tmp->password);
strcpy(emp[i]->user_type, tmp->user_type);
emp[i]->id = tmp->id;
i++;
}
free(tmp->first_name);
free(tmp->last_name);
free(tmp->user_name);
free(tmp->password);
free(tmp->user_type);
free(tmp);
fclose(f);
return emp;
}
void update_Gym_emp(Employees** emp, int* num) {
remove("Gym Employees.txt");
FILE* f = fopen("Gym Employees.txt", "w");
if (f == NULL) {
printf("Failed opening the file. Exiting!\n");
exit(1);
}
int i;
for (i = 0; i < num[0]; i++) {
fprintf(f, "%s#%s#%ld#%s#%s#%s#", emp[i]->first_name, emp[i]->last_name, emp[i]->id, emp[i]->user_name, emp[i]->password, emp[i]->user_type);
}
fclose(f);
}
here is one way the code could be written.
Notice that the first function reads from a file and creates a 2D list of Employee records
Notice that the second function writes to that same file from the 2D list of Employee records
Notice the string lengths for the call to fscanf() are one less than the related input buffer size because when scanning a string, the function will always append a NUL byte to the string
Strongly suggest defining the Employee struct as follows rather than the way it is currently defined:
struct Employee
{
char first_name[20];
char last_name[20];
long id;
char user_name[20];
char password[10];
char user_type[20];
};
Now, the proposed code
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Employee
{
char *first_name;
char *last_name;
long id;
char *user_name;
char *password;
char *user_type;
};
typedef struct Employee Employees;
// prototypes
void cleanup( Employees **emp );
Employees** Init_Gym_emp(Employees** emp, int* num)
{
FILE* f = fopen("Gym Employees.txt", "r");
if (f == NULL)
{
perror("fopen for Gym Employees.txt for input failed");
exit(1);
}
// implied else, fopen successful
char buffer[1024]; // input work area
// get count of records in file
while ( fgets(buffer, sizeof(buffer), f) )
{
num[0]++;
}
// step back to beginning of file to read/parse each record
if( fseek(f, 0, SEEK_SET) )
{ // then fseek failed
perror( "fseek to start of file failed" );
fclose( f );
exit( EXIT_FAILURE );
}
// implied else, fseek successful
// allocate array of pointers large enough for all records in input file
if( NULL == (*emp = malloc((size_t)num[0] * sizeof(Employees*) ) ) )
{
perror("malloc for array of pointers to Employee records failed");
cleanup( emp );
fclose( f );
exit(1);
}
// clear all pointers to NULL, to make cleanup easier
memset( *emp, '\0', (size_t)num[0] * sizeof( Employees* ));
char first_name[20];
char last_name[20];
long id;
char user_name[20];
char password[10];
char user_type[20];
int i = 0;
while( i < num[0] && fgets( buffer, sizeof(buffer), f ) )
{
if( 6 != sscanf(buffer,
"%19[^#]# %19[^#]# %ld# %19[^#]# %9[^#]# %19[^#]",
first_name,
last_name,
&id,
user_name,
password,
user_type) )
{ // then sscanf failed
perror( "sscanf for fields of emp record failed" );
cleanup( emp );
fclose( f );
exit( EXIT_FAILURE );
}
// implied else, sscanf successful
// get room for one employee record
if( NULL == (emp[i] = malloc(sizeof(Employees)) ) )
{
perror("malloc for new employee record failed");
cleanup( emp );
fclose( f );
exit( EXIT_FAILURE );
}
// implied else, malloc successful
(*emp)[i].first_name = strdup( first_name );
(*emp)[i].last_name = strdup( last_name );
(*emp)[i].user_name = strdup( user_name );
(*emp)[i].password = strdup( password );
(*emp)[i].user_type = strdup( user_type );
(*emp)[i].id = id;
i++;
} // end while
fclose(f);
return emp;
} // end function: Init_Gym_emp
void update_Gym_emp(Employees** emp, int* num)
{
FILE* f = fopen("Gym Employees.txt", "w");
if (f == NULL)
{
perror("fopen for Gym Employees.txt for write failed");
cleanup( emp );
exit(1);
}
// implied else, fopen successful
for (int i = 0; i < num[0]; i++)
{
fprintf(f, "%s#%s#%ld#%s#%s#%s#",
(*emp)[i].first_name,
(*emp)[i].last_name,
(*emp)[i].id,
(*emp)[i].user_name,
(*emp)[i].password,
(*emp)[i].user_type);
}
fclose(f);
} // end function: update_Gym_emp
I've written a simple C program to convert char into Tokens. Things work fine but I'm unable to understand why the size variable value is changing.
typedef struct _token {
int val;
} Token;
void parse( char* code, int size, Token** tokens ) {
int i = 0;
for (; i < size; i++) {
tokens[i] = malloc(sizeof(Token));
tokens[i]->val = code[i];
}
}
int execute( char *path ) {
char* code;
if ( read_file( path, &code ) != 0 ) {
return -1;
}
int size = strlen(code) - 1;
printf("BEFORE PARSE: %d\n", size); // 1st printf
Token *tokens;
parse( code, size, &tokens );
printf("AFTER PARSE: %d\n", size); // 2nd printf
return 0;
}
if code contains "abcde", the output is:
BEFORE PARSE: 5
AFTER PARSE: 142786584
The second printf displays different values on different runs.
Please help !
PS: I'm a C noob !
EDIT:
int read_file(char* path, char** code) {
FILE* fp = fopen ( path , "rb" );
if( !fp ) {
return -1;
}
fseek( fp , 0L , SEEK_END);
long lSize = ftell( fp );
rewind( fp );
/* allocate memory for entire content */
*code = calloc( 1, lSize+1 );
if( !*code ) {
fclose( fp );
return -1;
}
/* copy the file into the buffer */
if( 1 != fread( *code , lSize, 1 , fp) ) {
fclose(fp);
return -1;
}
fclose( fp );
return 0;
}
You have a typical case of buffer overflow.
char* code;
Allocates a pointer to character (typically 8 bytes), not a buffer to hold your file data.
Same with
Token *tokens;
When you write to tokens in parse you overwrite part of your stack and size with it.
Allocate enough memory for them!
char * code = malloc(0x1000);
Token *tokens = malloc(0x100 * sizeof(Token *));
And pass the pointer, not it's address:
read_file( path, code );
parse( code, size, tokens );
Here is corrected code:
typedef struct _token {
int val;
} Token;
void parse( char* code, int size, Token* tokens ) {
int i = 0;
for (; i < size; i++) {
// you already have memory now
tokens[i]->val = code[i];
}
}
int execute( char *path ) {
char* code = malloc(0x1000);
if ( read_file( path, code ) != 0 ) {
return -1;
}
int size = strlen(code) - 1;
printf("BEFORE PARSE: %d\n", size); // 1st printf
Token *tokens = calloc(sizeof(Token), 0x100);
parse( code, size, tokens );
printf("AFTER PARSE: %d\n", size); // 2nd printf
return 0;
}
It is because tokens is never initialized. Change it to:
Tokens **tokens = malloc(sizeof(Tokens *) * size);
Don't forget to free the memory when you are done with it:
for (; i < size; i++) {
free(tokens[i]);
}
free(tokens);