I have a c code which wrote in my Mac laptop in Xcode but it didn't work in Linux system.
I run this code by two ways:
1.One is run in Eclipse but the while loop didn't look like finish. Please find the message below:
Please wait while calculating...
But not more message in the console. It looks like while loop can't finish by some reason.
2.The second way is that I complier the code directly in Linux environment by the command:
cc -std=c99 main.c -o main
Then run by the command:
./main
The message shows that:
Please wait while calculating... Segmentation fault (core dumped)
I checked by gdb
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7a9bd4a in ?? () from /lib/x86_64-linux-gnu/libc.so.6
My data is saved in:
/home/alan_yu/workspace/scandi.csv
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
char **split(char *line, char sep, int fields) {
char **r = (char **)malloc(fields * sizeof(char*));
int lptr = 0, fptr = 0;
r[fptr++] = line;
while (line[lptr]) {
if (line[lptr] == sep) {
line[lptr] = '\0';
r[fptr] = &(line[lptr+1]);
fptr++;
}
lptr++;
}
return r;
}
int cmpfunc (const void * a, const void * b)
{
return *(double *)a > *(double *)b ? 1 : -1;
}
#define LINE_SIZE 1000000
#define EXPECTED_STOCK_SIZE 10000000
void calculate2(char * fileName) {
printf("Please wait while calculating...\n");
// Open the file for reading.
FILE *file = fopen(fileName, "r");
// maximun size of the line to read.
// memory allocation for the line to read.
char* line = malloc(LINE_SIZE);
// char **stockNameArray = malloc( sizeof(char *) * EXPECTED_STOCK_SIZE);
// int stockNameArrayPos = 0;
double *bidArray = malloc( sizeof(double) * EXPECTED_STOCK_SIZE );
int bidArrayPos = 0;
double *askArray = malloc( sizeof(double) * EXPECTED_STOCK_SIZE);
int askArrayPos = 0;
double *spreadArray = malloc( sizeof(double) * EXPECTED_STOCK_SIZE);
int spreadArrayPos = 0;
double sum=0;
int i=0,j=0;
while (fgets(line, LINE_SIZE, file)!= NULL){
// printf("Please wait while ...%d\n ", j);
j++;
char **fields = split(line, ',', 15);
const char * volvbEquity = "VOLVB SS Equity";
int comp = strcmp(fields[0], volvbEquity);
if (comp == 0) {
double bidValue = atof(fields[2]);
double askValue = atof(fields[3]);
bidArray[bidArrayPos++] = bidValue;
askArray[askArrayPos++] = askValue;
if (askValue - bidValue > 0) {
double spreadValue = ((askValue - bidValue) / (askValue + bidValue) * 20000);
spreadArray[spreadArrayPos++] = spreadValue;
sum = sum + spreadValue;
}
}
}
//quick sort the spread
qsort(spreadArray, spreadArrayPos, sizeof(double), cmpfunc);
int mediumPos;
double mean;
double medium;
if(spreadArrayPos % 2 == 0) {
mediumPos = spreadArrayPos / 2;
medium = (spreadArray[mediumPos] + spreadArray[mediumPos+1]) / 2;
} else {
mediumPos = (spreadArrayPos)/2 + 1;
medium = spreadArray[mediumPos];
}
mean = sum / spreadArrayPos;
printf("Please find mean and medium %f %f\n", mean, medium);
free(bidArray);
free(askArray);
free(spreadArray);
}
int main(int argc, char **argv) {
calculate2("/home/alan_yu/workspace/scandi.csv");
return(0);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
void split(char *line, char sep, char **fields) {
int lptr = 0, fptr = 0;
fields[fptr++] = line;
while (line[lptr]) {
if (line[lptr] == sep) {
line[lptr] = '\0';
fields[fptr] = &(line[lptr+1]);
fptr++;
}
lptr++;
}
}
int cmpfunc (const void * a, const void * b) {
return *(double *)a > *(double *)b ? 1 : -1;
}
#define LINE_SIZE 1000000
#define EXPECTED_STOCK_SIZE 10000000
#define COLUMN_NUM 15
void calculate2(char * fileName) {
printf("Please wait while calculating...\n");
// Open the file for reading.
FILE *file = fopen(fileName, "r");
// maximun size of the line to read.
// memory allocation for the line to read.
char* line = malloc(LINE_SIZE);
// char **stockNameArray = malloc( sizeof(char *) * EXPECTED_STOCK_SIZE);
// int stockNameArrayPos = 0;
double *bidArray = malloc( sizeof(double) * EXPECTED_STOCK_SIZE );
int bidArrayPos = 0;
double *askArray = malloc( sizeof(double) * EXPECTED_STOCK_SIZE);
int askArrayPos = 0;
double *spreadArray = malloc( sizeof(double) * EXPECTED_STOCK_SIZE);
int spreadArrayPos = 0;
double sum=0;
int i=0,j=0;
while (fgets(line, LINE_SIZE, file)!= NULL){
// printf("Please wait while ...%d\n ", j);
j++;
char **fields = malloc(sizeof(char *) * COLUMN_NUM);
split(line, ',', fields);
const char * volvbEquity = "VOLVB SS Equity";
int comp = strcmp(fields[0], volvbEquity);
if (comp == 0) {
double bidValue = atof(fields[2]);
double askValue = atof(fields[3]);
bidArray[bidArrayPos++] = bidValue;
askArray[askArrayPos++] = askValue;
if (askValue - bidValue > 0) {
double spreadValue = ((askValue - bidValue) / (askValue + bidValue) * 20000);
spreadArray[spreadArrayPos++] = spreadValue;
sum = sum + spreadValue;
}
}
// free memory for fields.
free(fields);
}
// free memory for the line variable.
free(line);
//quick sort the spread
qsort(spreadArray, spreadArrayPos, sizeof(double), cmpfunc);
int mediumPos;
double mean;
double medium;
if(spreadArrayPos % 2 == 0) {
mediumPos = spreadArrayPos / 2;
medium = (spreadArray[mediumPos] + spreadArray[mediumPos+1]) / 2;
} else {
mediumPos = (spreadArrayPos)/2 + 1;
medium = spreadArray[mediumPos];
}
mean = sum / spreadArrayPos;
printf("Please find mean and medium %f %f\n", mean, medium);
free(bidArray);
free(askArray);
free(spreadArray);
}
int main(int argc, char **argv) {
calculate2("/home/alan_yu/workspace/scandi.csv");
return(0);
}
On Linux, always run the program in valgrind if it is crashing.
It will not only tell you exactly what is wrong in your code, but also specify what code lines are responsible for the error.
You need to check the return value of fopen! I would suggest doing the same thing for malloc, but it's much less likely that malloc is failing due to a missing file or typographical error particularly if you're allocating large chunks! You wouldn't want to dereference a null pointer, right?
I'm assuming each line has at least four comma-separated fields, because you're using fields[3]. You should probably work out how to guard against using uninitialised values here. I'd start by re-engineering split so that you have some terminal NULL value or something in its output (and while we're on that topic, don't forget to free the return value).
Is it possible that you might be dividing by zero? That'd be something else you need to guard against.
Shouldn't cmpfunc return 0 when items are equal? I've seen implementations crash when return values for comparison functions for qsort and bsearch are inconsistent.
You claimed below in a comment that your lines have fifteen commas. This implies that you have sixteen fields (count them below), since the number of fields is n+1 where n is the number of separators.
field1, field2, field3, field4,
field4, field6, field7, field8,
field9, field10,field11,field12,
field13,field14,field15,field16
There are fifteen commas and sixteen fields in this table. You're only allocating enough for fifteen fields, however. This is a buffer overflow, more typical undefined behaviour.
Finally, I find out the problem comes from the
while (fgets(line, LINE_SIZE, file)!= NULL){
char **fields = split(line, ',', 15);
I have changed it to
char **fields = malloc(sizeof(char *) * 15 * 10000);
while (fgets(line, LINE_SIZE, file)!= NULL){
I haven't try to allocate a large memory to **fields after the while loop due to it takes too much memory to my machine.
It looks like under gcc compile that if I do:
while (fgets(line, LINE_SIZE, file)!= NULL){
char **fields = split(line, ',', 15);
It won't overwrite the **fields from last time. But it works in Mac
Not sure is that correct?
In the end, thanks for all of you guys help for my problem.
Related
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");
}
}
this is another issue I'm stuck with. First of all I'm trying to read a level-4 matlab file which contains information exported from PicoScope 6, it reads four arrays from the file, A, Tstart, Tinterval and Length. Array number one is the largest by far, it contains 1000004 values, however the other three only contains one value each. When I exectue the code below it successfully reads the file, stores it into a multidimensional array but fails when I'm trying to use the array.
#include <jni.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <matio.h>
#include "ReadMatFile.h"
//macros
#define getLength(x) (sizeof(x) / sizeof(x[0]))
//variables
double *dataMatrix[4];
int innerSize[getLength(dataMatrix)];
//functions
jobjectArray convertToArray(JNIEnv *env, double **data, int length1D,
int *length2D);
JNIEXPORT jdoubleArray JNICALL Java_ReadMatFile_readMatFile(JNIEnv *env,
jobject object, jstring str) {
const char *fileName = (*env)->GetStringUTFChars(env, str, 0);
mat_t *matfp;
matvar_t *matvar;
matfp = Mat_Open(fileName, MAT_ACC_RDONLY | MAT_FT_MAT4);
if ( NULL == matfp) {
fprintf(stderr, "Error opening MAT file %s\n", fileName);
return NULL;
}
int i = 0;
while ( NULL != (matvar = Mat_VarReadNext(matfp))) {
double *data = (double*) (matvar->data);
dataMatrix[i] = data;
innerSize[i] = (int) matvar->nbytes / matvar->data_size;
Mat_VarFree(matvar);
matvar = NULL;
i++;
}
Mat_Close(matfp);
(*env)->ReleaseStringUTFChars(env, str, fileName);
int s;
for(s = 0; s < innerSize[0]; s++)
printf("A[%d] = %e\n", s, dataMatrix[0][s]); /* Fails here */
return NULL;
//return convertToArray(env, dataMatrix, getLength(dataMatrix) ,innerSize);
}
jobjectArray convertToArray(JNIEnv *env, double **data, int length1D,
int *length2D) {
jsize outerSize = (jsize) length1D;
jclass class = (*env)->FindClass(env, "[D");
jobjectArray outer = (*env)->NewObjectArray(env, outerSize, class, 0);
jsize i;
for (i = 0; i < outerSize; i++) {
jsize innerSize = (jsize) length2D[i];
jdoubleArray inner = (*env)->NewDoubleArray(env, innerSize);
(*env)->SetDoubleArrayRegion(env, inner, 0, innerSize, data[i]);
(*env)->SetObjectArrayElement(env, outer, i, inner);
(*env)->DeleteLocalRef(env, inner);
}
return outer;
}
What is the cause of this? It creates a minidump when I run this application. Is the array too large?
A fix for this and also a explanation of what is wrong would be much appreciated!
Thanks in advance folks.
I suspect your problem is in the following code:
double *data = (double*) (matvar->data);
dataMatrix[i] = data;
innerSize[i] = (int) matvar->nbytes / matvar->data_size;
Mat_VarFree(matvar); // whoopsie
If Mat_VarFree does what I think it does, matvar->data is no longer a valid pointer, meaning dataMatrix[i] is no longer a valid pointer, hence the crash.
I think what you intend to do is something more along the lines of
innerSize[i] = matvar->nbytes / matvar->data_size;
dataMatrix[i] = malloc( sizeof *dataMatrix[i] * innerSize[i] );
if ( dataMatrix[i] )
memcpy( dataMatrix[i], matvar->data, matvar->nbytes );
Mat_VarFree( matvar );
that is, create a local copy of the data in matvar->data and save it to your dataMatrix. In your original code, all you copied was a pointer value; you never created a separate copy of your data.
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I seem to be going in circles with this project! I get so many errors of 'dereferencing pointer to incomplete type', and have quite a few others. it seems like when I fix one another one will pop up to take its place!
It's my first time using hash tables, and I admit that I am rather lost but I think I made a very good start at least. Any input as to how to solve my 'dereferencing pointer to incomplete type' problems would be amazing!
htable.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "htable.h"
struct htablerec {
int size;
int num_entries;
hashing_t method;
char **keys;
int *freqs;
int *stats;
};
void *emalloc(size_t s) {
void *result = malloc(s);
if (NULL == result) {
fprintf(stderr, "Memory allocation failed!\n");
exit(EXIT_FAILURE);
}
return result;
}
/*moves pointer to point to something appropriate*/
htable htable_new(int capacity) {
int i;
htable ht = emalloc(sizeof *ht);
ht->size = size;
ht->method = method;
ht->num_keys = 0;
ht->keys = emalloc(size * sizeof ht->keys[0]);
ht->freqs = emalloc(size * sizeof ht->freqs[0]);
ht->stats = emalloc(size * sizeof ht->stats[0]);
for(i = 0; i<size; i++){
ht->keys[i] = NULL;
ht->freqs[i] = 0;
ht->stats[i] = 0;
}
return ht;
}
static unsigned int htable_step(htable h, unsigned int i_key){
return 1 + (i_key % (h->size - 1));
}
static unsigned int htable_wtoi(char *word){
unsigned int result = 0;
while(*word != '\0') result = (*word++ +31 * result);
return result;
}
static unsigned int htable_hash(htable h, unsigned int i_key){
return i_key % h->size;
}
void htable_free(htable h) {
int i;
for(i = 0; i<h->size; i++){
if(h->keys[i] != NULL){
free(h->keys[i]);
}
}
if(h->keys != NULL){
free(h->keys);
}
if(h->freqs != NULL){
free(h->freqs);
}
free(h);
}
static unsigned int htable_word_to_int(char *word) {
unsigned int result = 0;
while (*word != '\0') {
result = (*word++ + 31 * result);
}
return result;
}
int htable_insert(htable h, char *str) {
int num_collisions = 0;
int i_key = htable_wtoi(key);
int pos = htable_hash(h, i_key);
int step = 1;
if(h->method == DOUBLE)
step = htable_step(h, i_key);
while(h->keys[pos]!=NULL &&
strcmp(h->keys[pos],key)!=0 &&
num_collisions < h->size ){
pos = htable_hash(h, pos + step);
num_collisions++;
}
if(h->keys[pos] == NULL){
h->keys[pos] = emalloc((strlen(key)+1) * sizeof h->keys[0][0]);
strcpy(h->keys[pos],key);
h->stats[h->num_keys] = num_collisions;
h->num_keys++;
}
if(num_collisions >= h->size) /* We must be full, so return zero.*/
return 0;
return ++(h->freqs[pos]);
}
static int htable_search(htable h, char *key){
int num_collisions = 0;
int i_key = htable_wtoi(key);
int pos = htable_hash(h, i_key);
int step = 1;
if(h->method == DOUBLE)
step = htable_step(h, i_key);
while(h->keys[pos]!=NULL &&
strcmp(h->keys[pos],key)!=0 &&
num_collisions < h->size ){
pos = htable_hash(h, pos + step);
num_keys++;
}
if(num_keys >= h->size)
return 0;
else
return h->freqs[pos];
}
void htable_print(htable h, FILE *stream){
int i;
for(i = 0; i<h->size; i++){
if(h->keys[i] != NULL)
fprintf(stream, "%d\t%s\n",i, h->freqs[i], h->keys[i]);
}
}
void htable_print_entire_table(htable h, FILE *stream) {
int i;
for (i=0; loop < h->capacity; i++) {
if (h->key[i] != NULL) {
fprintf("%d\t%s\n", h->freqs[i], h->key[i]);
}
}
}
/**
* Prints a line of data indicating the state of the hash table when
* it is a given percentage full.
*
* The data is printed out right justified (with the given field widths,
* and decimal places) in this order:
*
* - How full the hash-table is as a percentage (4)
* - How many keys are in the hash-table at that point (11)
* - What percentage of those keys were placed 'at home' (12, 1 dp)
* - The average number of collisions per key placed (12, 2 dp)
* - The maximum number of collisions while placing a key (12)
*
* #param h the hash-table to get data from.
* #param stream the place to send output to.
* #param percent_full the point at which to print the statistics.
* If the hashtable is less full than that, then
* nothing will be printed.
*/
static void print_stats_line(htable h, FILE *stream, int percent_full) {
int current_entries = h->capacity * percent_full / 100;
double average_collisions = 0.0;
int at_home = 0;
int max_collisions = 0;
int i = 0;
if (current_entries > 0 && current_entries <= h->num_keys) {
for (i = 0; i < current_entries; i++) {
if (h->stats[i] == 0) {
at_home++;
}
if (h->stats[i] > max_collisions) {
max_collisions = h->stats[i];
}
average_collisions += h->stats[i];
}
fprintf(stream, "%4d%11d%12.1f%12.2f%12d\n", percent_full,
current_entries, at_home * 100.0 / current_entries,
average_collisions / current_entries, max_collisions);
}
}
void htable_print_stats(htable ht, FILE *stream, int num_stats) {
int i;
fprintf(stream, "Percent Current Percent Average Maximum\n");
fprintf(stream, " Full Entries At Home Collisions Collisions\n");
fprintf(stream, "-----------------------------------------------------\n");
for (i = 1; i <= num_stats; i++) {
print_stats_line(ht, stream, 100 * i / num_stats);
}
fprintf(stream, "-----------------------------------------------------\n\n");
}
htable.h
#ifndef HTABLE_H
#define HTABLE_H
#include <stdio.h>
typedef struct hashtable *htable;
typedef enum hashing_e { LINEAR, DOUBLE } hashing_t;
extern htable htable_new(int size);
extern void htable_destroy(htable ht);
extern int htable_insert(htable h, char *key);
extern int htable_search(htable h, char *key);
extern void htable_print(htable h, FILE *stream);
extern void htable_print_stats(htable ht, FILE *stream, int num_stats);
#endif
main.c (given by tutor for project to fit)
/**
* #file main.c
* #author Iain Hewson
* #date August 2012
*
* This program is written to test the hash table ADT specified in
* Cosc242 assignment two. It creates a hash table which can use
* linear-probing or double-hashing as a collision resolution
* strategy. Various options are provided which make it possible to
* examine a hash table as well as see how it performs while being
* filled.
*/
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include "mylib.h"
#include "htable.h"
/* A boolean type which can be TRUE or FALSE */
typedef enum bool_e {FALSE, TRUE} bool_t;
/* function declarations */
static void usage(char *progname);
static void setup(int argc, char **argv, bool_t *double_hashing,
bool_t *entire_table, bool_t *print_stats,
int *snapshots, int *tablesize);
/**
*
* Creates a hash-table and inserts words into it read from stdin.
* Arguments on the command line alter the behaviour of the program
* as follows:
* - -d Use double hashing (linear probing is the default)
* - -e Display entire contents of hash-table on stderr
* - -n NUM Show NUM statistics snapshots (if -p is used)
* - -p Print stats info instead of frequencies & words
* - -s SIZE Use the first prime >= SIZE as htable size
* - -h Display this message
*
* By default each word and it's frequency are printed to stdout.
*
* #param argc the number of command-line arguments.
* #param argv an array of strings containing the command-line arguments.
*
* #return EXIT_SUCCESS if the program is successful.
*/
int main(int argc,char **argv) {
bool_t entire_table = FALSE, double_hashing = FALSE, print_stats = FALSE;
int tablesize = 0, snapshots = 0;
char word[256];
htable ht;
setup(argc, argv, &double_hashing, &entire_table, &print_stats,
&snapshots, &tablesize);
ht = htable_new(tablesize, (double_hashing) ? DOUBLE_H : LINEAR_P);
while (getword(word, sizeof word, stdin) != EOF) {
htable_insert(ht, word);
}
if (entire_table) {
htable_print_entire_table(ht, stderr);
}
if (print_stats) {
htable_print_stats(ht, stdout, snapshots);
} else {
htable_print(ht, stdout); /* print words and frequencies */
}
htable_free(ht);
return EXIT_SUCCESS;
}
/**
* Prints out a usage message to stderr outlining all of the options.
* #param prog_name the name of the program to include in usage message.
*/
static void usage(char *prog_name) {
fprintf(stderr, "Usage: %s [OPTION]... <STDIN>\n\n%s%s", prog_name,
"Perform various operations using a hash-table. By default read\n"
"words from stdin and print them with their frequencies to stdout.\n\n"
" -d Use double hashing (linear probing is the default)\n"
" -e Display entire contents of hash-table on stderr\n",
" -n NUM Show NUM stats snapshots (if -p is used)\n"
" -p Print stats info instead of frequencies & words\n"
" -s SIZE Use the first prime >= SIZE as htable size\n\n"
" -h Display this message\n\n");
}
/**
* Handle options given on the command-line by setting a number of
* variables appropriately. May call usage() if incorrect arguments
* or -h given.
*
* #param argc the number of command-line arguments.
* #param argv an array of strings contain the command-line arguments.
* #param double_hashing set to TRUE if -d given
* #param entire_table set to TRUE if -e given
* #param snapshots set to NUM if -n NUM given and NUM > 0 else set to 10
* #param print_stats set to TRUE if -p given
* #param tablesize set to SIZE if -t SIZE given and SIZE > 0 else set to 113
*/
static void setup(int argc, char **argv, bool_t *double_hashing,
bool_t *entire_table, bool_t *print_stats,
int *snapshots, int *tablesize) {
const char *optstring = "dehpn:s:";
char option;
while ((option = getopt(argc, argv, optstring)) != EOF) {
switch (option) {
case 'd':
*double_hashing = TRUE;
break;
case 'e':
*entire_table = TRUE;
break;
case 'p':
*print_stats = TRUE;
break;
case 'n':
*snapshots = atoi(optarg);
break;
case 's':
*tablesize = atoi(optarg);
break;
case 'h':
default:
usage(argv[0]);
exit(EXIT_SUCCESS);
}
}
/* set default values if nothing sensible entered */
if (*tablesize < 1) *tablesize = 113;
if (*snapshots < 1) *snapshots = 10;
}
mylib.c
#include <stdlib.h>
#include "mylib.h"
/**************************
* *
* emalloc *
* *
**************************
Used to handle new memory allocation to a pointer and handle exceptions
which may arrise if memory allocation fails, which happens all the time
when you try and enter negative values.
PARAMETERS: s = calculated size of required memory.
RETURN VALUE: a pointer of any type.
*/
void *emalloc(size_t s){
void *result = malloc(s);
if(NULL == result){
fprintf(stderr, "Memory allocation failed!\n");
exit(EXIT_FAILURE);
}
return result;
}
/**************************
* *
* erealloc *
* *
**************************
Handles the reallocation of an updated amount of memory to an existing
with existing data attached.
PARAMETERS: p = the existing pointer we would like additional memory
allocated to.
s = calculated size of required memory.
RETURN VALUE: a pointer of any type.
*/
void *erealloc(void *p, size_t s){
void *result = realloc(p,s);
if(NULL == result){
fprintf(stderr, "Memory allocation failed!\n");
exit(EXIT_FAILURE);
}
return result;
}
/**************************
* *
* getword *
* *
**************************
Is used to read input from the designated file stream (standard in for the
assignment). Getword removes white space with the first while loop. And only
returns one word. Maintaining continous input is therefore the responsibility
of the calling function.
PARAMETERS: s = the pointer to the character array.
limit = the maximum size a word can be.
stream = where to read from.
RETURN VALUE: the integer value of the character at s[0]. The string s does
not need to be returned, since it is an array and is passed as
a memory address. If no chars were read into the string s, then
s[0] would have the '\0' [NULL] value which equates to 0 if used
in a boolean equation.
*/
int getword(char *s, int limit, FILE *stream){
int c;
while(!isalnum( c = getc(stream)) && c != EOF);
if(c == EOF)
return EOF;
else
*s++ = tolower(c);
while(--limit > 0){
if(isalnum(c = getc(stream)))
*s++ = tolower(c);
else if('\'' == c) continue;
else break;
}
*s = '\0';
return s[0];
}
/**************************
* *
* stoi *
* *
**************************
Not using this function now.
PARAMETERS: s = string representation of a number.
RETURN VALUE: the integer value.
*/
int stoi(char *s){
int i,j,r;
int sign = 1;
i=1;
r=0;
for(j=my_strlen(s)-1; j>=0; j--){
if(j == 0 && s[j] == '-')
sign = -1;
else {
if(s[j]>='0' && s[j]<='9'){
r+=((s[j]-'0')*i);
i*=10;
} else {
fprintf(stderr, "Invalid input for String to int\n");
exit(EXIT_FAILURE);
}
}
}
return r * sign;
}
/**************************
* *
* my_strlen *
* *
**************************
I am using my own string length function, but I wrote it with the stoi
function, so am using it here. Perhaps not as safe as the library
functions?
PARAMETERS: s = a string delimited by the NULL character.
RETURN VALUE: the number of characters in the string.
*/
int my_strlen(char *s){
int i=0;
while(s[i]!='\0')
i++;
return i;
}
/**************************
* *
* factors *
* *
**************************
Another unrequired function used to calculate the possiblity of factorisation.
PARAMETERS: x = An integer to be factored towards.
RETURN VALUE: 0 if x has factors, 1 if x is a prime number.
*/
static int factors(int x){
int f = 2;
while(f*f < x){
if(x % f == 0){
return 0;
} else {
f++;
}
}
return 1;
}
/**************************
* *
* prime_gt *
* *
**************************
Used in conjunction with factors to find factorless integers. We increment
bound until it is truely prime.
Bound - We start with bound, sending it to the factors function. If it is
a prime number, then stop searching. Otherwise loop until we find
an prime integer larger than the input integer.
PARAMETERS: s = the input integer.
RETURN VALUE: Bound, for it is now a prime number.
*/
static int prime_gt(int s){
int bound = s;
while(bound > 0){
if(factors(bound))
break;
else
bound++;
}
return bound;
}
/**************************
* *
* relative_prime *
* *
**************************
Decides on a prime number to use to set the table size to.
PARAMETERS: s = the required size of the table.
RETURN VALUE: the newer beter prime number size for the table.
*/
unsigned int relative_prime(int s){
return prime_gt(s);
}
Sorry for it being so big, it's ok if it's just a complete unfixable jumble.
You don't seem to have defined struct hashtable anywhere. You need to say somewhere what fields that struct should actually contain, at the moment there is only a forward declaration in htable.h.
Such a forward declaration just says that the type exists, but not how it exactly looks like. Therefore it is considered an incomplete type, until the compiler sees a full definition of it.
Cause the definition of struct hashtable does not exist, the following line creates an alias of an incomplete pointer type (htable).
typedef struct hashtable *htable;
It is impossible to deference such pointer (the compiler doesn't know the different fields of your structure).
In your file htable.c, maybe you meant :
/* instead of struct htablered */
struct htable {
int size;
int num_entries;
hashing_t method;
char **keys;
int *freqs;
int *stats;
};
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].
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.