Resizing 2D char array causes exception - c

I'm new to C, so please forgive me for noobie mistakes, we all need to start somewhere.
My task is to get some lines from a big file and store each line in a 2d array, where li[0] is the first line and so on...
On top of that, I have no ideia whats the size of this 'big text', so I came up with the code bellow to resize the array every time it reaches critical size (is there an easier way to do that?). Also, I could not find a better way to define the line size other than setting it very high.
The code bellow fails on the second time it resizes with an exception on this line char **temp = realloc(lin, LINE_QUANT * sizeof(char*));
Whats causing that exception?
#include <stdio.h>
#include <stdlib.h>
#define LINE_TAM 200
size_t PAL_QUANT = 100, LINE_QUANT = 3;
int main(){
int i = 0;
char **li = (char**) malloc(LINE_QUANT * sizeof(char*));
char fname[30];
FILE *arq = NULL;
// alloc word container
for (i=0; i < LINE_QUANT; i++)
li[i] = malloc(LINE_TAM * sizeof(char));
if(li == NULL) return 0;
//(ommited file opener)
i = 0;
//getting words from file (unknown size)
while(fgets(li[i], LINE_TAM, arq) != NULL){
while(i >= LINE_QUANT - 1) resizeArr(li);
i++;
}
return 1;
}
void resizeArr(char **lin){
int i;
LINE_QUANT = LINE_QUANT * 2;
char **temp = realloc(lin, LINE_QUANT * sizeof(char*));
if(temp) {
lin = temp;
for (i = LINE_QUANT/2; i < LINE_QUANT; i++){
lin[i] = malloc(LINE_TAM * sizeof(char*));
if (lin[i] == NULL)
exit(1);
}
}
else
exit(1);
free(temp);
}

Since each element of the array will be the same size, use could be made of a pointer to array, (*li)[LINE_TAM].
Because resizeArr modifies the pointer, either a pointer to the pointer needs to be passed to the function or the function needs to return the pointer.
realloc will take care of any required free, so do not free the pointers.
This uses stdin but it can be modified to use a FILE*.
Enter stop to exit the loop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LINE_TAM 200
void resizeArr ( size_t *line_quant, char (**lin)[LINE_TAM]);
int main(){
int i = 0;
char (*li)[LINE_TAM] = NULL;//pointer to array
size_t Line_Quant = 3;
// alloc word container
if ( NULL == ( li = malloc( sizeof *li * Line_Quant))) {
fprintf ( stderr, "malloc problem\n");
return 1;
}
i = 0;
//getting words from file (unknown size)
while ( fgets ( li[i], LINE_TAM, stdin) != NULL) {
if ( 0 == strcmp ( li[i], "stop\n")) {
break;
}
if (i >= Line_Quant - 1) {
resizeArr ( &Line_Quant, &li);
}
i++;
}
free ( li);
return 1;
}
void resizeArr ( size_t *line_quant, char (**lin)[LINE_TAM]) {
int i;
char (*temp)[LINE_TAM] = realloc ( *lin, sizeof **lin * *line_quant * 2);
if ( temp) {//success
*lin = temp;//assign back to caller
*line_quant *= 2;//increase by two
for ( i = *line_quant / 2; i < *line_quant; i++) {
(*lin)[i][0] = 0;
}
}
else {
fprintf ( stderr, "realloc problem\n");
}
}

Related

How can I return list in C?

I am trying to divide the string with *, and return the divided strings, as follows.
abc*d*efg*hijk -> [abc,d,efg,hijk]
This is my code, where *pattern is the given string, and I first count the number of asterisk(cnt), and make a empty list with length cnt. But it keeps getting the error and I don't get it... Can anyone help me?
error message
value computed is not used (*star_cnt++;)
function returns address of local variable(return units;)
Number 2 is my main error. I can't return the list
int Slice(char *pattern) {
int *star_cnt;
int cnt;
*star_cnt = *pattern;
cnt = 0;
while (*star_cnt != '\0') {
if (*star_cnt == '*') {
cnt++;
}
*star_cnt++;
}
int units[cnt];
int *unit;
int unit_cnt;
unit_cnt = 0;
*unit = *pattern;
while (*unit != '\0') {
int *new_unit;
while (*unit != '*'){
*new_unit = *unit;
unit++;
new_unit++;
}
unit++;
units[unit_cnt] = *new_unit;
}
return units;
I felt there were a number of things wrong, and that looking at a working example might actually help a bit more here.
You could try something like this:
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
/**
* #fn Slice()
* #param [IN] pattern - pointer to string to be analysed
* #param
* #return pointer to array for strings, array is terminated by NULL
* */
char** Slice(char *pattern) {
char *star_cnt;
int cnt;
char** resultlist;
star_cnt = pattern;
cnt = 0;
while (*star_cnt != '\0') {
if (*star_cnt == '*') {
cnt++;
}
star_cnt++;
}
printf("%d items\n",cnt+1);
resultlist = malloc(sizeof(char*) * (cnt+2));
memset(resultlist,0,sizeof(char*) * (cnt+2));
star_cnt = pattern;
cnt = 0;
resultlist[cnt] = star_cnt;
//printf("item %d: %s\n",cnt,resultlist[cnt]);
cnt++;
while (*star_cnt != '\0') {
if (*star_cnt == '*') {
*star_cnt = '\0';
resultlist[cnt] = star_cnt+1;
//printf("item %d: %s\n",cnt,resultlist[cnt]);
cnt++;
}
star_cnt++;
}
return resultlist;
}
int main()
{
char working_string[] = "abc*d*efg*hijk";
char* backup_string = strdup(working_string);
char** list = NULL;
list = Slice(working_string);
int i;
i = 0;
if (list != NULL)
{
while(list[i] != NULL)
{
printf("%d : %s\n",i,list[i]);
i++;
}
free(list);
}
printf("original_string = %s\n",backup_string);
free(backup_string);
}
It produces an output like this:
4 items
0 : abc
1 : d
2 : efg
3 : hijk
original_string = abc*d*efg*hijk
The Slice function basically returns a pointer to char* strings, and the array list is terminated with a NULL in the last element. Keep in mind that in this solution the original string is modified so it cannot be used again.
For storing and returning the result you can also define string container like:
struct c_str_container{
char **arr;
size_t size;
};
And then you can define functions like init_c_str_container, add_element_to_c_str_container and free_c_str_container for dealing with the container.
then you can write the substrings function with using strchr function for finding the delimiters and splitting the string in to sub-strings.
Finally you can use this function to create the container and then after displaying the result from the container (and possibly doing other things with the container) you free the allocated memory by the predefined function free_c_str_container:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct c_str_container{
char **arr;
size_t size;
};
void init_c_str_container(struct c_str_container *container){
container->arr = NULL;
container->size = 0;
}
int add_element_to_c_str_container(struct c_str_container *container, const char *txt, size_t length){
char **newarr = (char **) realloc(container->arr, (container->size + 1) * (sizeof(char *)));
if(!newarr){
newarr = (char **) malloc((container->size + 1) * (sizeof(char *)));
if(!newarr){
return -1;
}else{
for(size_t counter = container->size; counter--;){
newarr[counter] = container->arr[counter];
}
if(container->size){
free(container->arr);
}
}
}
newarr[container->size] = malloc((length + 1) * sizeof(char));
memcpy(newarr[container->size], txt, length);
newarr[container->size][length] = '\0';
container->arr = newarr;
++container->size;
return 0;
}
void free_c_str_container(struct c_str_container *container){
for(size_t counter = container->size; counter--;){
free(container->arr[counter]);
}
free(container->arr);
container->size = 0;
}
struct c_str_container substrings(const char *input, const char delimiter){
const char *input_end = input + strlen(input);
struct c_str_container container;
init_c_str_container(&container);
while(strchr(input, delimiter) == input){
++input;
}
const char *end_point;
while((end_point = strchr(input, delimiter))){
add_element_to_c_str_container(&container, input, (end_point - input));
while(strchr(end_point, delimiter) == end_point){
++end_point;
}
input = end_point;
}
if(input < input_end){
add_element_to_c_str_container(&container, input, (input_end - input));
}
return container;
}
int main(void) {
struct c_str_container container = substrings("***as***we*grow*up", '*');
printf("number of elements is : %zu\n", container.size);
for(size_t counter = 0; counter < container.size; ++counter){
printf("element %zu is : %s\n", counter, container.arr[counter]);
}
free_c_str_container(&container);
printf("now elements are : %zu\n", container.size);
return EXIT_SUCCESS;
}
for the test string ="***as***we*grow*up" delimeter = '*' the result of the program is:
number of elements is : 4
element 0 is : as
element 1 is : we
element 2 is : grow
element 3 is : up
now elements are : 0

Dynamically allocated Array of pointers to structures

I am trying to allocate enough space for an array of pointers to structure(City) with
City **ptrArray = (City **)calloc(numberOfLines, sizeof(City*));
char tempArray[100];
char* temp = tempArray;
int slength;
for (int i = 0; i < numberOfLines; i++)
{ //Allocates enough memory for array of length of string
fscanf(fPtr, "%99[^:] %*c", tempArray);
slength = strlen(temp);
ptrArray[i] = (City*)malloc(sizeof(int)+(sizeof(char)*slength));
strcpy(ptrArray[i]->cityName, temp);
//fscanf(fPtr, "%d", ptrArray[i]->temperature);
}
This is where I read the data from a file into the array. The debugger(visual studio) only shows one cell in ptrArray and it seems that the data gets lost.
numberOfLines is an assigned int value.
tempArray is a temporary holding place for the strings read from the file.
temp is a pointer to tempArray.
Bonus issue: The commented out line at the bottom of the for loop breaks the code every time and I have no clue why.
edit: I added the code where I initialized temp and tempArray.
Also it is a weird call to malloc because the assignment specifies allocating exactly enough memory for the string and an int instead of having a maximum value for the string. And here is my struct
typedef struct{
int temperature;
char cityName[100];
}City;
Thank you very much for you help!
For dynamic allocation of cityName.
typedef struct{
int temperature;
char *cityName;// pointer to char
}City;
City **ptrArray = calloc(numberOfLines, sizeof(City*));
if ( ptrArray == NULL) {
printf ( "calloc failed\n");
exit(1);
}
char tempArray[100];
int slength;
for (int i = 0; i < numberOfLines; i++)
{
if ( ( fscanf(fPtr, "%99[^:] %*c", tempArray)) != 1) {
//handle problem - break or return or exit.
}
slength = strlen(tempArray);
ptrArray[i] = malloc( sizeof(City));// memory for structure
if ( ptrArray[i] == NULL) {
printf ( "malloc failed\n");
exit ( 1);
}
ptrArray[i]->cityName = malloc( 1 + slength));// memory for cityName + 1 for '\0'
if ( ptrArray[i]->cityName == NULL) {
printf ( "malloc failed\n");
exit (1);
}
strcpy(ptrArray[i]->cityName, tempArray);
if ( ( fscanf(fPtr, "%d", &ptrArray[i]->temperature)) != 1) {
//handle problem break or return or exit
}
}
Memory allocated should also be freed when it is no longer needed. numberOfLines and ptrArray may have different names outside this function and the corresponding names would be used instead.
for ( i = 0; i < numberOfLines; i++) {
free ( ptrArray[i]->cityName);
free ( ptrArray[i]);
}
free ( ptrArray);

Having trouble when allocating memory when passing a double pointers address into a triple pointer

I'm creating a double pointer and sending in the address to allocate memory, which requires a triple pointer. Also, i am creating single pointers (goals and assists) and sending their addresses to allocate memory, which requires double pointers. I think the problem lies in allocation of memory, but i cant figure it out. I keep seg faulting whenever i run the readLinesFromFile function. It does not segfault when I try running allocateMemory function by itself. The problem could also be in the readLinesFromFile function
int main (int argc, char **argv)
{
int numPlayers = 0;
if (argc != 3)
{
printf("Missing text file");
return 0;
}
char **playerNames;
int *goals, *assists;
FILE *filePtr = fopen(argv[1],"r");
if(filePtr == NULL)
{
printf("\nFile is empty");
return 0;
}
numPlayers = countLinesInFile(filePtr);
allocateMemory(&goals,&assists,&playerNames,numPlayers);
readLinesFromFile(filePtr,goals,assists,playerNames,numPlayers);
}
void allocateMemory(int **goals, int **assists, char *** names, int size)
{
int i = 0;
*goals = malloc(MAX_NAME * sizeof(int));
*assists = malloc(MAX_NAME * sizeof(int));
*names = malloc(MAX_NAME * sizeof(char*));
for (i = 0; i < size; i++)
{
(names[i]) = malloc(MAX_NAME * sizeof(char*));
}
}
void readLinesFromFile(FILE *fptr, int *goals, int *assists, char **names, int numLines)
{
int i = 0, j = 0, x = 0;
char players[MAX_LINE];
char *tokenPtr;
fptr = fopen(INPUT,"r");
for(i = 0; i < numLines; i++)
{
fgets(players,MAX_LINE, fptr);
tokenPtr = strtok(players," ");
strcpy((*(names+i)), tokenPtr);
while (tokenPtr != NULL)
{
tokenPtr = strtok(NULL," ");
if (x = 0)
{
goals[i] = atoi(tokenPtr);
x = 1;
}
else
{
assists[i] = atoi(tokenPtr);
x = 0;
}
}
}
}
Assuming MAX_NAME is the maximum length of a player's name, this should work:
void AllocateMemory(char *** pppNames, int ** ppGoals, int ** ppAssists, size_t sizePlayersMax)
{
*pppNames = malloc(sizePlayersMax * sizeof **pppNames);
*ppGoals = malloc(sizePlayersMax * sizeof **ppGoals);9
*ppAssists = malloc(sizePlayersMax * sizeof **ppAssists);
{
size_t sizePlayersCount = 0;0
for (; sizePlayersCount < sizePlayersMax; ++sizePlayersCount)
{
(*pppNames)[sizePlayersCount] = calloc(MAX_NAME + 1, sizeof *((*pppNames)[sizePlayersCount]));
}
}
}
To prevent the app from overwriting memory in case of really long player names you might like to change this line:
strcpy((*(names+i)), tokenPtr);
to become:
if (tokenPtr)
strncpy((*(names+i)), tokenPtr, MAX_NAME);
This would truncate the player names stored to a maximum of MAX_NAME characters. The latter is the size AllocateMemory() use minus 1. This one spare character is needed for the 0/NUL to terminate the character-array so it could be used as a "string".
Finally also this is dangerous:
while (tokenPtr != NULL)
{
tokenPtr = strtok(NULL," ");
if (x = 0)
{
Better do like this:
while (NULL != (tokenPtr = strtok(NULL," ")))
{
if (x = 0)
{

How do I pass an array of Pointers to a structure and allocate the members

ok, heres my code. I'm trying to pass an array of pointers to a structure to a function.
I need to dynamically allocate each structure and put a pointer to that structure in the array.
When I malloc the second time thru it gets a heap error.
HELP
#define MAXSTRUCTS 50
#define MAXBUFF 100
typedef struct {
char fullName[41];
char address[41];
char cityState[41];
char zipcode[11];
} Persons;
int readData(Persons *structPtrs[]);
int main(void) {
int totalStructs;
Persons *structPtrs[MAXSTRUCTS];
totalStructs = 0;
structPtrs[0] = NULL;
totalStructs = readData(structPtrs);
}
int readData(Persons *strptr[]) {
int tStructs = 0;
int recs;
char inRecord[MAXBUFF];
Persons *tmpPtr;
tStructs = 0;
for (recs=0; recs < MAXSTRUCTS; recs++) {
if (gets(inRecord) != NULL) {
strptr[recs] = (Persons *)malloc( sizeof(Persons));
tmpPtr = strptr[recs];
strncpy(tmpPtr->fullName,inRecord,MAXBUFF);
gets(inRecord);
strncpy(tmpPtr->address,inRecord,MAXBUFF);
gets(inRecord);
strncpy(tmpPtr->cityState,inRecord,MAXBUFF);
gets(inRecord);
strncpy(tmpPtr->zipcode,inRecord,MAXBUFF);
strptr[recs] = tmpPtr;
tStructs++;
}
else {
if ( recs = 0 ) {
exit (0);
}
recs=MAXSTRUCTS;
}
}
return(tStructs);
}
You are doing everything right in regard of passing an array of pointers and allocating memory. What leading to a heap corruption is incorrect usage of strncpy function. The arrays where you are trying to copy data to are slightly smaller than MAXBUFF in all cases. To fix this, you have to specify the size of destination array instead of MAXBUFF. For example, instead of:
strncpy(tmpPtr->fullName,inRecord,MAXBUFF);
... do (assuming that buffer is already filled with \0 symbols):
strncpy(tmpPtr->fullName,inRecord, sizeof(tmpPtr->fullName) - 1);
Also, using gets function is not recommended as well as it could easily lead to buffer overruns. Try using fgets instead.
Here is your modified example that works:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAXSTRUCTS 2
#define MAXBUFF 100
typedef struct {
char fullName[41];
char address[41];
char cityState[41];
char zipcode[11];
} Persons;
int readData(Persons *structPtrs[]);
int main ()
{
int totalStructs;
int recs;
Persons *structPtrs[MAXSTRUCTS];
totalStructs = 0;
structPtrs[0] = NULL;
totalStructs = readData(structPtrs);
for(recs = 0; recs < totalStructs; ++recs) {
printf ("Record #%d - %s\n", recs + 1, structPtrs[recs]->fullName);
}
return 0;
}
int readData(Persons *strptr[])
{
int tStructs = 0;
int recs;
char inRecord[MAXBUFF];
Persons *tmpPtr;
tStructs = 0;
for (recs=0; recs < MAXSTRUCTS; ++recs) {
memset (inRecord, 0, sizeof(inRecord));
if (fgets(inRecord, sizeof (inRecord) - 1, stdin))
{
strptr[recs] = (Persons *)malloc(sizeof(Persons));
tmpPtr = strptr[recs];
memset (tmpPtr, 0, sizeof(Persons));
strncpy(tmpPtr->fullName,inRecord,sizeof(tmpPtr->fullName) - 1);
fgets(inRecord, sizeof (inRecord) - 1, stdin);
strncpy(tmpPtr->address,inRecord,sizeof(tmpPtr->address) - 1);
fgets(inRecord, sizeof (inRecord) - 1, stdin);
strncpy(tmpPtr->cityState,inRecord, sizeof(tmpPtr->cityState) - 1);
fgets(inRecord, sizeof (inRecord) - 1, stdin);
strncpy(tmpPtr->zipcode,inRecord, sizeof (tmpPtr->zipcode) - 1);
strptr[recs] = tmpPtr;
tStructs++;
} else {
if ( recs = 0 ) {
exit (0);
}
recs=MAXSTRUCTS;
}
}
return(tStructs);
}
int readDataToRecord( Persons *eachEntry[] ) {
int numEntries = 0 ;
Persons *tempPtr ;
for( int i=0 ; i < NUM_OF_RECORDS; ++i ) {
eachEntry[i] = ( Record * ) malloc( sizeof( Record ) ) ;
memset( eachEntry[i], 0, sizeof( Record ) ) ;
tempPtr = eachEntry[i] ;
fgets( tempPtr->firstName, sizeof( tempPtr->firstName ), stdin ) ;
fgets( tempPtr->secondName, sizeof( tempPtr->secondName), stdin ) ;
eachEntry[i] = tempPtr ;
++numEntries ;
}
return numEntries ;
}
This would also efficiently do the job. Once you have new record, you would any how have the memory allocated for each of its member. So you can directly fgets to that variable.
#Vlad : Please let me know if I am wrong.

Program Segmentation Faults on return 0/fclose/free. I think I have memory leaks but can't find them. Please help!

I am trying to write a Huffman encoding program to compress a text file. Upon completetion, the program will terminate at the return statement, or when I attempt to close a file I was reading from. I assume I have memory leaks, but I cannot find them. If you can spot them, let me know (and a method for fixing them would be appreciated!).
(note: small1.txt is any standard text file)
Here is the main program
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define ASCII 255
struct link {
int freq;
char ch[ASCII];
struct link* right;
struct link* left;
};
typedef struct link node;
typedef char * string;
FILE * ofp;
FILE * ifp;
int writebit(unsigned char);
void sort(node *[], int);
node* create(char[], int);
void sright(node *[], int);
void Assign_Code(node*, int[], int, string *);
void Delete_Tree(node *);
int main(int argc, char *argv[]) {
//Hard-coded variables
//Counters
int a, b, c = 0;
//Arrays
char *key = (char*) malloc(ASCII * sizeof(char*));
int *value = (int*) malloc(ASCII * sizeof(int*));
//File pointers
FILE *fp = fopen(argv[1], "r");
if (fp == NULL) {
fprintf(stderr, "can't open %s\n", argv[1]);
return 0;
}
//Nodes
node* ptr;//, *head;
node* array[ASCII];
//
int u, carray[ASCII];
char str[ASCII];
//Variables
char car = 0;
int inList = 0;
int placeinList = -1;
int numofKeys;
if (argc < 2) {
printf("Usage: huff <.txt file> \n");
return 0;
}
for (a = 0; a < ASCII; a++) {
key[a] = -1;
value[a] = 0;
}
car = fgetc(fp);
while (!feof(fp)) {
for (a = 0; a < ASCII; a++) {
if (key[a] == car) {
inList = 1;
placeinList = a;
}
}
if (inList) {
//increment value array
value[placeinList]++;
inList = 0;
} else {
for (b = 0; b < ASCII; b++) {
if (key[b] == -1) {
key[b] = car;
break;
}
}
}
car = fgetc(fp);
}
fclose(fp);
c = 0;
for (a = 0; a < ASCII; a++) {
if (key[a] != -1) {
array[c] = create(&key[a], value[a]);
numofKeys = c;
c++;
}
}
string code_string[numofKeys];
while (numofKeys > 1) {
sort(array, numofKeys);
u = array[0]->freq + array[1]->freq;
strcpy(str, array[0]->ch);
strcat(str, array[1]->ch);
ptr = create(str, u);
ptr->right = array[1];
ptr->left = array[0];
array[0] = ptr;
sright(array, numofKeys);
numofKeys--;
}
Assign_Code(array[0], carray, 0, code_string);
ofp = fopen("small1.txt.huff", "w");
ifp = fopen("small1.txt", "r");
car = fgetc(ifp);
while (!feof(ifp)) {
for (a = 0; a < ASCII; a++) {
if (key[a] == car) {
for (b = 0; b < strlen(code_string[a]); b++) {
if (code_string[a][b] == 48) {
writebit(0);
} else if (code_string[a][b] == 49) {
writebit(1);
}
}
}
}
car = fgetc(ifp);
}
writebit(255);
fclose(ofp);
ifp = fopen("small1.txt", "r");
fclose(ifp);
free(key);
//free(value);
//free(code_string);
printf("here1\n");
return 0;
}
int writebit(unsigned char bitval) {
static unsigned char bitstogo = 8;
static unsigned char x = 0;
if ((bitval == 0) || (bitval == 1)) {
if (bitstogo == 0) {
fputc(x, ofp);
x = 0;
bitstogo = 8;
}
x = (x << 1) | bitval;
bitstogo--;
} else {
x = (x << bitstogo);
fputc(x, ofp);
}
return 0;
}
void Assign_Code(node* tree, int c[], int n, string * s) {
int i;
static int cnt = 0;
string buf = malloc(ASCII);
if ((tree->left == NULL) && (tree->right == NULL)) {
for (i = 0; i < n; i++) {
sprintf(buf, "%s%d", buf, c[i]);
}
s[cnt] = buf;
cnt++;
} else {
c[n] = 1;
n++;
Assign_Code(tree->left, c, n, s);
c[n - 1] = 0;
Assign_Code(tree->right, c, n, s);
}
}
node* create(char a[], int x) {
node* ptr;
ptr = (node *) malloc(sizeof(node));
ptr->freq = x;
strcpy(ptr->ch, a);
ptr->right = ptr->left = NULL;
return (ptr);
}
void sort(node* a[], int n) {
int i, j;
node* temp;
for (i = 0; i < n - 1; i++)
for (j = i; j < n; j++)
if (a[i]->freq > a[j]->freq) {
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
void sright(node* a[], int n) {
int i;
for (i = 1; i < n - 1; i++)
a[i] = a[i + 1];
}
If your program is crashing on what is otherwise a valid operation (like returning from a function or closing a file), I'll near-guarantee it's a buffer overflow problem rather than a memory leak.
Memory leaks just generally mean your mallocs will eventually fail, they do not mean that other operations will be affected. A buffer overflow of an item on the stack (for example) will most likely corrupt other items on the stack near it (such as a file handle variable or the return address from main).
Probably your best bet initially is to set up a conditional breakpoint on writes to the file handles. This should happen in the calls to fopen and nowhere else. If you detect a write after the fopen calls are finished, that will be where your problem occurred, so just examine the stack and the executing line to find out why.
Your first problem (this is not necessarily the only one) lies here:
c = 0;
for (a = 0; a < ASCII; a++) {
if (key[a] != -1) {
array[c] = create(&key[a], value[a]);
numofKeys = c; // DANGER,
c++; // WILL ROBINSON !!
}
}
string code_string[numofKeys];
You can see that you set the number of keys before you increment c. That means the number of keys is one less than you actually need so that, when you access the last element of code_string, you're actually accessing something else (which is unlikely to be a valid pointer).
Swap the numofKeys = c; and c++; around. When I do that, I at least get to the bit printing here1 and exit without a core dump. I can't vouch for the correctness of the rest of your code but this solves the segmentation violation so anything else should probably go in your next question (if need be).
I can see one problem:
strcpy(str, array[0]->ch);
strcat(str, array[1]->ch);
the ch field of struct link is a char array of size 255. It is not NUL terminated. So you cannot copy it using strcpy.
Also you have:
ofp = fopen("small1.txt.huff", "w");
ifp = fopen("small1.txt", "r");
If small1.txt.huff does not exist, it will be created. But if small1.txt it will not be created and fopen will return NULL, you must check the return value of fopen before you go and read from the file.
Just from counting, you have 4 separate malloc calls, but only one free call.
I would also be wary of your sprintf call, and how you are actually mallocing.
You do an sprintf(buf, "%s%d", buf, c[i]) but that can potentially be a buffer overflow if your final string is longer than ASCII bytes.
I advise you to step through with a debugger to see where it's throwing a segmentation fault, and then debug from there.
i compiled the program and ran it with it's source as that small1.txt file and got "can't open (null)" if the file doesn't exist or the file exist and you give it on the command like ./huf small1.txt the program crashes with:
Program terminated with signal 11, Segmentation fault.
#0 0x08048e47 in sort (a=0xbfd79688, n=68) at huf.c:195
195 if (a[i]->freq > a[j]->freq) {
(gdb) backtrace
#0 0x08048e47 in sort (a=0xbfd79688, n=68) at huf.c:195
#1 0x080489ba in main (argc=2, argv=0xbfd79b64) at huf.c:99
to get this from gdb you run
ulimit -c 100000000
./huf
gdb --core=./core ./huf
and type backtrace
You have various problems in your Code:
1.- mallocs (must be):
//Arrays
char *key = (char*) malloc(ASCII * sizeof(char));
int *value = (int*) malloc(ASCII * sizeof(int));
sizeof(char) == 1, sizeof(char *) == 4 or 8 (if 64 bits compiler is used).
2.- Buffer sizes 255 (ASCII) is too short to receive the contents of array[0]->ch + array[1]->ch + '\0'.
3.- Use strncpy instead of strcpy and strncat instead of strcat.
4.- key is an array of individuals chars or is a null terminated string ?, because you are using this variable in both ways in your code. In the characters counting loop you are using this variables as array of individuals chars, but in the creation of nodes you are passing the pointer of the array and copying as null terminated array.
5.- Finally always check your parameters before used it, you are checking if argc < 2 after trying to open argv[1].

Resources