Trouble debugging binarysearch function in C - c

i'm trying to make a binary search that searches through an ordered file of numbers. Although, even though it worked in "main" before I converted this into a function, it has managed to have some weird behavior after my fseek().
Any suggestions?
int BinarySearch(FILE *cp, char *CPR, int *position) {
int i, lines, current_line;
double CPR_number, CPR_check;
char CPR_check_string[CPR_LEN];
sscanf(CPR, "%lf", &CPR_number);
fseek(cp, 0L, SEEK_END);
lines = ftell(cp)/12;
current_line = ftell(cp)/2 - ((ftell(cp)/2) % 12);
for (i = 0; i < log10(lines)/log10(2); i++) {
fseek(cp, current_line, SEEK_SET);
/* Read CPR as string */
fscanf(cp, "%[0-9]", CPR_check_string);
/* Convert to number */
sscanf(CPR_check_string, "%lf", &CPR_check);
if (CPR_number == CPR_check) {
printf("This happens\n");
*position = ftell(cp);
return TRUE;
} else if (CPR_number < CPR_check) {
current_line = ftell(cp)/2 - ((ftell(cp)/2) % 12);
} else if (CPR_number > CPR_check) {
current_line = ftell(cp) + ftell(cp)/2 - ((ftell(cp) + ftell(cp)/2) % 12);
}
}
return FALSE;
}
It doesn't seem to run the rest of the code.
Thanks in advance.

I found my answer, it was my FILE pointer that was off, it had to be a pointer to a pointer so FILE **.

Related

Problems on computing statistics and parsing a text file

a must be simple question but I couldn't manage to do it.
I have to scan on a struct a text file with entries in this format:
{"data1","data2",number1,number2}
And compute first populating a struct.
Text of the exercise:
Consider the definition of the following structure
typedef struct {
char teamHome [30];
char teamHost [30];
int goalSquadraHome;
int goalSquadraOspite;
} match;
which is used to represent the result of a football match.
Write a function that takes as parameters an array of games and its size e
returns a result structure containing the following information:
the number of games won by the home team,
the number of games won by the visiting team,
the number of ties,
the name of the team that has scored the most goals in a match.
Then write a program that, given the array containing all 380 Serie A 2019/2020 matches,
print the information contained in the result.
The code is the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
char squadraCasa[30];
char squadraOspite[30];
int golSquadraCasa;
int golSquadraOspite;
} partita;
typedef struct {
int partite_casa;
int partite_ospite;
int pareggi;
char squad_magg_num_goal[30];
} risultato;
int main(){
FILE *fp;
risultato risultati;
int maxgoal = 0;
risultati.partite_casa = 0;
risultati.partite_ospite = 0;
risultati.pareggi = 0;
partita partite[380];
int i=0;
if((fp = fopen("partiteSerieA1920.txt","rt"))==NULL){
printf("Errore nell'apertura del file\n");
exit(1);
}
while(!feof(fp)){
fscanf(fp,"{\"%s\",\"%s\",%d,%d",partite[i].squadraCasa,partite[i].squadraOspite,partite[i].golSquadraCasa,partite[i].golSquadraOspite);
i++;
}
for(i=0;i<380;i++){
if(partite[i].golSquadraCasa>partite[i].golSquadraOspite){
risultati.partite_casa++;
}else if(partite[i].golSquadraCasa<partite[i].golSquadraOspite){
risultati.partite_ospite++;
}else
risultati.pareggi++;
if(partite[i].golSquadraCasa>maxgoal){
strncpy(partite[i].squadraCasa,risultati.squad_magg_num_goal,30);
maxgoal = partite[i].golSquadraCasa;
}
if(partite[i].golSquadraOspite>maxgoal){
strncpy(partite[i].squadraOspite, risultati.squad_magg_num_goal,30);
maxgoal = partite[i].golSquadraOspite;
}
}
fclose(fp);
printf("%d %d %d %s\n",risultati.partite_casa,risultati.partite_ospite,&risultati.pareggi,&risultati.squad_magg_num_goal);
return 0;
}
Please let me know how to arrange it properly.
There may be other issues, but certainly your flow control is wrong. Instead of the incorrect while/feof loop(Why is “while ( !feof (file) )” always wrong?), try something like:
partita *p = partite;
while( 4 == fscanf(fp, "{\"%29s\",\"%29s\",%d,%d",
p->squadraCasa,
p->squadraOspite,
&p->golSquadraCasa,
&p->golSquadraOspite
) ){
p++;
}
Give this a try, its a bit of a different approach:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char squadraCasa[30];
char squadraOspite[30];
int golSquadraCasa;
int golSquadraOspite;
} partita;
typedef struct
{
int partite_casa;
int partite_ospite;
int pareggi;
char squad_magg_num_goal[30];
} risultato;
// solves given problem and stores results in risultato struct
risultato *getResult(partita **playedGames, int size)
{
risultato *result = malloc(sizeof(risultato));
result->partite_casa = 0;
result->partite_ospite = 0;
result->pareggi = 0;
int currentHighest = 0;
for (int i = 0; i < size; i++)
{
if (playedGames[i]->golSquadraCasa > playedGames[i]->golSquadraOspite){
result->partite_casa++;
if(playedGames[i]->golSquadraCasa > currentHighest ){
currentHighest = playedGames[i]->golSquadraCasa;
strcpy(result->squad_magg_num_goal, playedGames[i]->squadraCasa);
}
}
else if (playedGames[i]->golSquadraCasa < playedGames[i]->golSquadraOspite){
result->partite_ospite++;
if (playedGames[i]->golSquadraOspite > currentHighest){
currentHighest = playedGames[i]->golSquadraOspite;
strcpy(result->squad_magg_num_goal, playedGames[i]->squadraOspite);
}
}
else{
result->pareggi++;
}
}
return result;
}
// This is a custom parser of a line from the file
// data = {"data1","data2",number1,number2}
// return -> partita struct
partita *newGame(char *data){
partita *partite = malloc(sizeof(partita));
char* temp;
// Get Home Team
temp = strchr(data, ',') -1;
temp[0] = '\0';
strcpy(partite->squadraCasa, data + 2);
data = temp+1;
// Get Away Team
temp = strchr(data+1, ',') -1;
temp[0] = '\0';
strcpy(partite->squadraOspite, data + 2);
data = temp + 1;
// Get Home Score
temp = strchr(data + 1, ',');
temp[0] = '\0';
partite->golSquadraCasa = atoi(data + 1);
data = temp + 1;
// Get Away Score
temp = strchr(data, '}');
temp[0] = '\0';
partite->golSquadraOspite = atoi(data);
// Return game
return partite;
}
int main()
{
FILE *fp;
partita **partite = malloc(sizeof(partita *)); // list of size one, currently...
risultato *risultati;
char linea[50];
int indice = 0;
if ((fp = fopen("./partiteSerieA1920.txt", "rt")) == NULL)
{
printf("Errore nell'apertura del file\n");
exit(1);
}
// For each linea in the file, load a game into an array.
while (fgets(linea, 50,fp))
{
//chomp the \n
linea[strlen(linea)-1]='\0';
// increase size of list
partite = realloc(partite, sizeof(partita *) * (indice + 1));
// insert game into array of games
partite[indice] = newGame(linea);
indice++;
}
risultati = getResult(partite, indice);
// Print risultato
printf("\n----RESULT----\nHome Wins: %d\nAway Wins: %d\nTies: %d\nTeam With Most Goals: %s\n\n", risultati->partite_casa, risultati->partite_ospite, risultati->pareggi, risultati->squad_magg_num_goal);
// free all allocated memory then return
for (int i = 0; i < indice;i++){
free(partite[i]);
}
free(partite);
free(risultati);
fclose(fp);
return 0;
}
I was trying to run your code but couldnt get it to parse data from the file properly so i made a quick parser for you (This is in the code above already):
partita *newGame(char *data){
partita *partite = malloc(sizeof(partita));
char* temp;
// Get Home Team
temp = strchr(data, ',') -1;
temp[0] = '\0';
strcpy(partite->squadraCasa, data + 2);
data = temp+1;
// Get Away Team
temp = strchr(data+1, ',') -1;
temp[0] = '\0';
strcpy(partite->squadraOspite, data + 2);
data = temp + 1;
// Get Home Score
temp = strchr(data + 1, ',');
temp[0] = '\0';
partite->golSquadraCasa = atoi(data + 1);
data = temp + 1;
// Get Away Score
temp = strchr(data, '}');
temp[0] = '\0';
partite->golSquadraOspite = atoi(data);
// Return game
return partite;
}
You can always try to use something similar to this to parse strings or lines that you bring in as I find it is more efficient to just code something that you know works to the specification you want.
Let me know if there is some problem with the code or would like to know more about the functionality of this. I tried to keep as much of this in Italian.
Cheers

Counting strings in C, using fgets and strstr

This is part of an assignment, so the instructions are clear and I'm not allowed to use anything other than what is specified.
The idea is simple:
1) Create an array of structs which hold a string and a count
2) Count the occurrence of the string in each struct and store the count in that struct
3) Print the strings and their number of occurrences
I have been explicitly told to use the fgets and strstr functions
Here is what I've got so far,
#define MAX_STRINGS 50
#define LINE_MAX_CHARS 1000
int main(){
int n = argc - 1;
if (n > MAX_STRINGS) {
n = MAX_STRINGS;
}
Entry entries[MAX_STRINGS];
char **strings = argv+1;
prepare_table(n, strings, entries);
count_occurrences(n, stdin, entries);
print_occurrences(n, entries);
}
void prepare_table (int n, char **strings, Entry *entries) {
// n = number of words to find
// entries = array of Entry structs
for (int i = 0; i < n; i++){
Entry newEntry;
newEntry.string = *(strings + 1);
newEntry.count = 0;
*(entries + i) = newEntry;
}
}
void print_occurrences (int n, Entry *entries) {
for (int i = 0; i < n; i++){
printf("%s: %d\n", (*(entries + i)).string, (*(entries + i)).count);
}
}
void count_occurrences (int n, FILE *file, Entry *entries) {
char *str;
while (fgets(str, LINE_MAX_CHARS, file) != NULL){
for (int i = 0; i < n; i++){ // for each word
char *found;
found = (strstr(str, (*(entries + i)).string)); // search line
if (found != NULL){ // if word found in line
str = found + 1; // move string pointer forward for next iteration
i--; // to look for same word in the rest of the line
(*(entries + i)).count = (*(entries + i)).count + 1; // increment occurrences of word
}
}
}
}
I know for a fact that my prepare_table and print_occurrences functions are working perfectly. However, the problem is with the count_occurrences function.
I've been given a test file to run which just tells me that I'm not producing the correct output. I can't actually see the output to figure out whats wrong
I'm new to pointers, so I'm expecting this to be a simple error on my part. Where is my program going wrong?
fgets(char * restrict str, int size, FILE * restrict stream) writes into the buffer at str... but you don't have a buffer at str. What is str? It's just a pointer. What's it pointing at? Garbage, because you haven't initialized it to something. So it might work or it might not (edit: by which I mean you should expect it not to work, and be surprised if it did, thank you commenters!).
You could fix that by allocating some memory first:
char *str = malloc(LINE_MAX_CHARS);
// do your stuff
free(str);
str = NULL;
Or even statically allocating:
char str[LINE_MAX_CHARS];
That's one problem I can see anyway. You say you don't have output, but surely you can add some debug statements using fprintf(stderr, "") at the very least..?

LibAIFF CloseFile: Pointer being freed was not allocated occurs randomly

I have written a piece of code that attempts to search a directory and its subfolders for two AIFF files and using the LibAIFF library to import and then perform some processing operations on them.
Part 1: Searching the directory for the files
For this part of the program, I need to look for the files (which can be thought of as identical AIFF files except for a difference in their filenames) with known names (for example SineSweepA.aiff and SineSweepB.aiff) and then construct the absolute path to it (the length of which I am unaware of (since my program needs to work on different computers where the AIFFs can be located within different subfolders within a MainDirectory - see code below) but know will be less than 200 characters in length). I am able to do this successfully and consistently using the following piece of code:
void file_search(char* parentDir, char* subFolder, char* filenamePrefix, char* tempString, char* tempFilepath, int* foundFlag, int* level);
int32_t *import_sweeps(char* sweepFilepath, uint64_t* numSamples, int* numChannels, double* samplingRate, int* bitDepth, int* segmentSize, int* importFlag);
int main()
{
...
char MainDirectory[200] = "/Users/rrr/Documents/Foldername1/";
char tempFilepath[200], tempFilepathR[200], parentDir[200], filenamePrefix[200], subFolder[200], tempString[200];
int level = 0, foundFlag = 0;
int numChannels = 0;
int bitDepth;
int segmentSize;
int importFlag = 0;
int32_t *sweepRfile = NULL;
uint64_t numSamples = 0, numSamplesR = 0;
unsigned long templen;
double samplingRate = 0.0;
char *sweepFilepath = NULL, *sweepFilepathR = NULL; // Allocated to specific size later
strcpy(parentDir, MainDirectory);
strcat(parentDir, "SubFolderName1/");
strcpy(tempFilepathR, parentDir);
strcpy(filenamePrefix, "KnownFilenamePrefix1");
// file_search() searches for a specific file with a known name and constructs the absolute path to the file and stores it in tempFilepathR. The function is shown further below.
file_search(parentDir, subFolder, filenamePrefix, tempString, tempFilepath, &foundFlag, &level);
if (foundFlag)
{
sprintf(tempFilepath, "%s%s/KnownFilenamePrefix1%s.aiff", parentDir, subFolder, subFolder);
sprintf(tempFilepathR, "%s%s/KnownFilenamePrefix2%s.aiff", parentDir, subFolder, subFolder);
}
...
(to be continued in Part 2 of my question below)
}
void file_search(char* dir, char* subfolder, char* fileprefix, char* filename, char* filepath, int*flag, int* level)
{
DIR *dp;
struct dirent *entry; // entry is a pointer to the structure "dirent" defined in <dirent.h>
struct stat statbuf; // the structure "stat" is defined in <stat.h>
if((dp = opendir(dir)) == NULL) {
fprintf(stderr,"Cannot open directory: %s\n", dir);
return;
}
chdir(dir); // this sets the working directory to the string pointed to by "dir"
while((entry = readdir(dp)) != NULL)
{
lstat(entry->d_name, &statbuf);
if(S_ISDIR(statbuf.st_mode)) // Tests for a directory
{
// Found a directory
if(strcmp(".",entry->d_name) == 0 || strcmp("..",entry->d_name) == 0)
{
// Ignore . and ..
continue;
}
if(level[0] < 1)
{
// Proceed down one level and search again
strcpy(subfolder,entry->d_name);
level[0] = level[0] + 1;
// Recursive function call
file_search(entry->d_name, subfolder, fileprefix, filename, filepath, postfilepath, flag, level);
level[0] = level[0] - 1;
if(flag[0] == 1)
{
// Exit loop if a file was found at a lower level
break;
}
}
}
else
{
sprintf(filename, "%s%s.aiff", fileprefix, subfolder);
if(strcmp(entry->d_name,filename) == 0)
{
// File found. Construct absolute path to file
sprintf(filepath, "%s%s/%s", filepath, subfolder, filename); // Pass filepath outside
flag[0] = 1; //Appropriate file found
break;
}
}
}
chdir("..");
closedir(dp);
}
So by using the above code, I am able to successfully search for two AIFF files with given filenames by searching through subfolders with a known MainDirectory, construct their absolute paths and store them in tempFilepath and tempFilepathR. The next step is to import these two files and this is where I run into a problem.
Part 2: Importing the files
The problem I run into is as follows: I implemented the LibAIFF library to import the files. The issue is that if I run the program, say N times, then on some of the runs, the first file gets imported but not the second, on other runs the second gets imported but not the first (note that if the first doesn't get imported, the program stops). Before I explain the error, please know that there is no issue with the AIFF files, for the sake of this problem you can assume they are identical and that even their absolute paths and filenames are identical except one has a suffix A.aiff and the other B.aiff. These file paths are stored as strings in identically defined variables (tempFilepath and tempFilepathR).
Here is the rest of the necessary part of my code continued from above
int main()
{
// Continued from above
...
// Copy over exact file paths (I had to do this because the function AIFF_OpenFile which is part of the LibAIFF library and shown below refused to accept a statically allocated char variable such as tempFilepath)
templen = strlen(tempFilepathR); // tempFilepath and tempFilepathR always have the same length
sweepFilepath = malloc(templen + 1);
strcpy(sweepFilepath, tempFilepath);
// Proceed to import the FIRST AIFF (returned to sweepRfile from import_sweeps())
sweepRfile = import_sweeps(sweepFilepath, &numSamples, &numChannels, &samplingRate, &bitDepth, &segmentSize, &importFlag);
if (importFlag) // The import was successful
{
free(sweepFilepath);
// Do some processing with the successfully imported AIFF
free(sweepRfile);
}
else // The import was unsuccessful and sweepRfile (which is usually malloc'ed in the import_sweeps() function is not malloc'ed
{
free(sweepFilepath);
}
// Now for the SECOND AIFF (I can overwrite a lot of the variables used for the first AIFF because I don't need them)
sweepFilepathR = malloc(templen + 1); // templen is assigned above
strcpy(sweepFilepathR, tempFilepathR);
// Proceed to import the SECOND AIFF (returned to sweepRfile from import_sweeps())
sweepRfile = import_sweeps(sweepFilepathR, &numSamplesR, &numChannels, &samplingRate, &bitDepth, &segmentSize, &importFlag);
if (importFlag) // The import was successful
{
free(sweepFilepathR);
// Do some processing with the successfully imported AIFF
free(sweepRfile);
}
else // The import was unsuccessful and sweepRfile (which is usually malloc'ed in the import_sweeps() function is not malloc'ed
{
free(sweepFilepathR);
}
...
// Rest of code in main is irrelevant because it doesn't even get there.
}
The break always occurs within the import_sweeps() function (sometimes for the first AIFF and sometimes for the second). The function is shown below
int32_t *import_sweeps(char* sweepFilepath, uint64_t* numSamples, int* numChannels, double* samplingRate, int* bitDepth, int* segmentSize, int* importFlag)
{
// Initialize files for importing */
AIFF_Ref fileref;
// Import Routine */
fileref = AIFF_OpenFile(sweepFilepath, F_RDONLY);
if(fileref)
{
// File opened successfully. Proceed to intialize files for getting information about AIFF file
uint64_t nSamples;
int nSamplePts, channels, bitsPerSample, segSize, temp;
double smpr;
// Get AIFF file format details
temp = AIFF_GetAudioFormat(fileref, &nSamples, &channels, &smpr, &bitsPerSample, &segSize);
if (temp < 1) {
fprintf(stderr,"Error getting audio format.\n");
AIFF_CloseFile(fileref);
return (int32_t) 0;
}
else
{
numSamples[0] = nSamples;
samplingRate[0] = smpr;
numChannels[0] = channels;
bitDepth[0] = bitsPerSample;
segmentSize[0] = segSize;
nSamplePts = ((int) nSamples)*channels;
int32_t *samples = malloc((nSamplePts+1) * sizeof(int32_t));
// Read AIFF
temp = AIFF_ReadSamples32Bit(fileref, samples, nSamplePts);
if (temp != -1)
{
AIFF_CloseFile(fileref);
importFlag[0] = 1;
return samples;
}
else
{
fprintf(stderr,"Unable to read AIFF.\n");
AIFF_CloseFile(fileref);
return (int32_t) 0;
}
}
}
else
{
fprintf(stderr,"Unable to open AIFF file.\n");
}
return (int32_t) 0;
}
Inside import_sweeps() above, the AIFF file is ALWAYS successfully read by calling the function AIFF_ReadSamples32Bit(fileref, samples, nSamplePts);. Therefore, the temp value is never -1. Whenever an error (as described above and I will give the actual error message below) happens, it ALWAYS occurs when it tries to call AIFF_CloseFile(fileref);.
Shown below are the functions AIFF_ReadSamples32Bit and AIFF_CloseFile as defined in the LibAIFF library.
int AIFF_ReadSamples32Bit(AIFF_Ref r, int32_t * samples, int nSamplePoints)
{
int n = nSamplePoints;
void *buffer;
int i, j;
size_t h;
size_t len;
int segmentSize;
int32_t *dwords;
int16_t *words;
int8_t *sbytes;
uint8_t *inbytes;
uint8_t *outbytes;
uint8_t x, y, z;
if (!r || !(r->flags & F_RDONLY))
return -1;
if (n % (r->nChannels) != 0)
return 0;
if (n < 1 || r->segmentSize == 0) {
if (r->buffer) {
free(r->buffer);
r->buffer = NULL;
r->buflen = 0;
}
return -1;
}
segmentSize = r->segmentSize;
len = (size_t) n * segmentSize;
if ((r->buflen) < len) {
if (r->buffer)
free(r->buffer);
r->buffer = malloc(len);
if (!(r->buffer)) {
return -1;
}
r->buflen = len;
}
buffer = r->buffer;
h = AIFF_ReadSamples(r, buffer, len);
if (h < (size_t) segmentSize) {
free(r->buffer);
r->buffer = NULL;
r->buflen = 0;
return 0;
}
n = (int) h;
if (n % segmentSize != 0) {
free(r->buffer);
r->buffer = NULL;
r->buflen = 0;
return -1;
}
n /= segmentSize;
switch (segmentSize) {
case 4:
dwords = (int32_t *) buffer;
for (i = 0; i < n; ++i)
samples[i] = dwords[i];
break;
case 3:
inbytes = (uint8_t *) buffer;
outbytes = (uint8_t *) samples;
n <<= 2; /* n *= 4 */
j = 0;
for (i = 0; i < n; i += 4) {
x = inbytes[j++];
y = inbytes[j++];
z = inbytes[j++];
#ifdef WORDS_BIGENDIAN
outbytes[i] = x;
outbytes[i + 1] = y;
outbytes[i + 2] = z;
outbytes[i + 3] = 0;
#else
outbytes[i] = 0;
outbytes[i + 1] = x;
outbytes[i + 2] = y;
outbytes[i + 3] = z;
#endif
}
n >>= 2;
break;
case 2:
words = (int16_t *) buffer;
for (i = 0; i < n; ++i) {
samples[i] = (int32_t) (words[i]) << 16;
}
break;
case 1:
sbytes = (int8_t *) buffer;
for (i = 0; i < n; ++i) {
samples[i] = (int32_t) (sbytes[i]) << 24;
}
break;
}
return n;
}
and
int AIFF_CloseFile(AIFF_Ref ref)
{
int r;
if (!ref)
return -1;
if (ref->flags & F_RDONLY) {
AIFF_ReadClose(ref); // BREAK OCCURS HERE EVERYTIME
r = 1;
} else if (ref->flags & F_WRONLY) {
r = AIFF_WriteClose(ref);
} else {
r = -1;
}
return r;
}
The break occurs at AIFF_ReadClose(ref); EVERYTIME. So I have also shown this function below.
static void AIFF_ReadClose(AIFF_Ref r)
{
if (r->buffer)
free(r->buffer);
if (r->buffer2)
free(r->buffer2); // THIS IS WHERE THE BREAK OCCURS EVERYTIME
Unprepare(r);
fclose(r->fd);
free(r);
return;
}
The break always occurs as shown above. The following is the error message: (25693,0x7fff7db87310) malloc: * error for object 0x4000000000000000: pointer being freed was not allocated
* set a breakpoint in malloc_error_break to debug
So basically, the above error occurs unpredictably. When it doesn't occur, my code works perfectly. Any help as to how I might solve this problem is much appreciated.
IF ANYONE IS WILLING TO DOWNLOAD THE LIBAIFF LIBRARY TO INVESTIGATE FURTHER AND HELP ME OUT, the link to the library is: http://aifftools.sourceforge.net/libaiff/.
Thanks in advance for any suggestions!
1, please confirm buffer2 has been initialized with NULL before using. In all your pasted codes, I can not find any assignment or memory allocation for buffer2.
2, please assign the pointer with NULL after calling free, like:
if (r->buffer)
{
free(r->buffer);
r->buffer = NULL;
}
if (r->buffer2)
{
free(r->buffer2);
r->buffer2 = NULL;
}
If all this can not resolve you problem, please give more code about buffer2.

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].

C Memory Allocation: Why there is not enough memory(250K only)

I am having trouble figuring out the reason why my .c code is having trouble allocating ~250K of memory. Here is the allocation code:
struct IMAGE {
int width, height, maxval;
char **data;
};
void raiseError(char *msg)
{
printf("%s", msg);
getch();
exit(1);
}
//...
IMAGE readPGM()
{
IMAGE image;
image.data = (char **) malloc(sizeof(char)*image.height);
//..
for (i=0; i<image.height; i++) {
image.data[i] = (char *) malloc(sizeof(char)*image.width);
if (image.data[i]=='\0') {
printf("%d\n", i);
raiseError("Not enough memory!..");
}
}
//..
}
//..
The program exits when i=116. image.width and image.height equals to 500 here, so I want 500x500=250000 bytes to be allocated here. But 116x500 = 58000 bytes are being allocated at maximum. So, is there something that limits it? Is there something wrong with my code? I am posting the full source below, just in case if it is necesarry. The idea is to read a PGM file into the structure IMAGE, process it and rewrite it in another file. As you can tell, it is not complete yet because I couldn't figure out a way to allocate more memory.
#include<stdio.h>
#include<conio.h>
#include<ctype.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#include<alloc.h>
struct IMAGE {
int width, height, maxval;
char **data;
};
void raiseError(char *msg)
{
printf("%s", msg);
getch();
exit(1);
}
char *toString(int num)
{
char sign = 0;
if (num<0) {
sign = -1;
num*=-1;
}
int numLen = 1;
if (sign<0) {
numLen++;
}
int tmpNum = num;
while (tmpNum>9) {
tmpNum /= 10;
numLen++;
}
char *result = (char *)malloc(sizeof(char)*(numLen+1));
result[numLen] = '\0';
char ch;
while (num>9) {
ch = (num%10)+'0';
num /= 10;
result[numLen-1] = ch;
numLen--;
}
result[numLen-1] = num + '0';
if (sign<0)
result[0] = '-';
return result;
}
int toInteger(char *line)
{
int i=strlen(line)-1;
int factor = 1;
int result = 0;
while (i>=0) {
result += factor*(line[i]-'0');
factor *= 10;
i--;
}
return result;
}
char *getNewParam(FILE *fp)
{
char ch = 'X';
char *newParam;
newParam = (char*) malloc(1);
newParam[0] = '\0';
int paramSize = 0;
while (!isspace(ch)) {
ch = fgetc(fp);
if (!isspace(ch)) {
if (ch=='#') {
while (fgetc(fp)!='\n');
continue;
}
paramSize++;
newParam = (char *) realloc(newParam, paramSize+1);
newParam[paramSize-1] = ch;
}
}
newParam[paramSize] = '\0';
return newParam;
}
IMAGE readPGM()
{
FILE *fp;
IMAGE image;
//Open the file.
fp = fopen("seeds2.pgm","r+b");
if (fp=='\0')
raiseError("File could not be opened!..");
//Check if it is a raw PGM(P5)
char *line;
line = getNewParam(fp);
if (strcmp(line, "P5")!=0)
raiseError("File is not a valid raw PGM(P5)");
int paramCount = 0;
int *pgmParams;
pgmParams = (int *)malloc(sizeof(int)*3);
while (paramCount<3) {
line = getNewParam(fp);
pgmParams[paramCount++] = toInteger(line);
}
int pixelSize;
if (pgmParams[2]>255)
pixelSize = 2;
else
pixelSize = 1;
image.width =pgmParams[0];
image.height =pgmParams[1];
image.maxval =pgmParams[2];
free(pgmParams);
image.data = (char **) malloc(sizeof(char)*image.height);
int i,j;
long sum = 0;
for (i=0; i<image.height; i++) {
image.data[i] = (char *) malloc(sizeof(char)*image.width);
sum += sizeof(char)*image.width;
if (image.data[i]=='\0') {
printf("%d\n", i);
raiseError("Not enough memory!..");
}
}
for (i=0; i<image.height; i++) {
for (j=0; j<image.width; j++) {
fread(&image.data[i][j], sizeof(char), image.width, fp);
}
}
fclose(fp);
return image;
}
void savePGM(IMAGE image)
{
FILE *fp = fopen("yeni.pgm", "w+b");
fprintf(fp, "P5\n%s\n%s\n%s\n",
toString(image.width), toString(image.height), toString(image.maxval));
int i,j;
for (i=0; i<image.height; i++) {
for (j=0; j<image.width; j++) {
fwrite(&image.data[i][j], sizeof(char), 1, fp);
}
}
fclose(fp);
}
int main()
{
clrscr();
IMAGE image = readPGM();
//process
savePGM(image);
getch();
return 0;
}
The answer to your question is in the comment you added to it. You are using an (antique) 16 bit x86 real mode compiler. A 16 bit virtual machine can address only 1Mb of memory in total, only 640Kb of which is normally accessible to programs, and is shared with the OS.
[edit in response to paxdiablo's comment]
Further to those restrictions the segmented addressing architecture also gives rise to a number of memory models where as little as 64kb may be the limit for specific memory areas.
Also the argument to malloc() has type size_t, which may only be 16-bit in this case - you should check. I recall using a variant called halloc() for large allocations. But short of using a DOS extender, there is still a 640kb limit.
[end edit]
There are a number of far better and free modern 32-bit compilers available. Dump the antique. I suggest VC++ Express Edition
Apart from that strictly:
if(image.data[i]=='\0')
should be
if(image.data[i]==0)
or
if(image.data[i]==NULL)
As it happens it will work in either case, but technically you are testing for a null-pointer not a NUL character.
I'm not going to read all that code -- this is a prime example of where you should give a minimal example to reproduce the problem -- but this line:
image.data = (char **) malloc(sizeof(char)*image.height);
is incorrect. It should have sizeof(char*). The statement as written should return a char* but you are casting it to char**.
FWIW, on my system, sizeof(char) returns 1 and sizeof(char*) returns 4, because a char is a single byte, and a char* is a pointer (aka a single word of 32 bits). So you actually allocated 1/4 of what you probably intended to allocate.
If you print out the value that you are passing to malloc, you will find out how much memory you are really asking for.

Resources