This perl script is modified from the #ikegami parallel arrays version to include test data.
On execution, it fails with this error message:
“The program can’t start because gsl.dll is missing from your computer. Try reinstalling the program to fix the problem.”
However, when a C program runs PolyFit it executes without error. The source code for it follows the perl script below.
gsl.dll is present in the same directory as PolyFitGSL.dll, D:/prjct/model/code/SRS1/binaries/:
# #ikegami parallel arrays version
use 5.014;
use strict;
use warnings;
use feature qw( state );
use Config qw( %Config );
use Win32::API qw( );
use constant PTR_SIZE => $Config{ptrsize};
use constant PTR_PACK_FORMAT =>
PTR_SIZE == 8 ? 'Q'
: PTR_SIZE == 4 ? 'L'
: die("Unrecognized ptrsize\n");
use constant PTR_WIN32API_TYPE =>
PTR_SIZE == 8 ? 'DWORD64'
: PTR_SIZE == 4 ? 'DWORD32'
: die("Unrecognized ptrsize\n");
# local definitions
my $fitorder = 3;
my #XVals = (1,2,3,4,5,6,7,8,9,10);
my #YVals = (12.36,12.32,12.31,12.37,12.44,12.44,12.5,12.46,12.48,12.51);
Win32::API::Type->typedef('uintptr_t' => PTR_WIN32API_TYPE);
my $dll = 'D:/prjct/model/code/SRS1/binaries/PolyFitGSL';
sub get_buffer_addr { unpack(PTR_PACK_FORMAT, pack('P', $_[0])) }
sub poly_fit {
my ($xvals, $yvals, $fitorder) = #_;
#$xvals == #$yvals
or croak("Mismatch in the number of X vals and Y vals");
state $PolyFit;
if (!$PolyFit) {
my $adjusted_proto = '
int __declspec PolyFit(
int numPts,
uintptr_t xVals,
uintptr_t yVals,
int fitOrder,
uintptr_t coef,
uintptr_t fitVals,
uintptr_t rSquared
)
';
$PolyFit = Win32::API::More->new($dll, $adjusted_proto)
or die("Can't link to PolyFit: $^E\n");
}
my $n = #$xvals;
my $xVals = pack("d$n", #$xvals);
my $yVals = pack("d$n", #$yvals);
my $coef = pack('d'.( $fitorder + 1 ), ( 0 )x( $fitorder + 1 ));
my $fit_vals = pack("d$n", ( 0 )x( $n ));
my $r_squared = pack('d', 0);
my $rv = $PolyFit->Call(
$n,
get_buffer_addr($xvals),
get_buffer_addr($yvals),
$fitorder,
get_buffer_addr($coef),
get_buffer_addr($fit_vals),
get_buffer_addr($r_squared),
);
# I'm assuming the return value indicates whether the call was successful or not?
return if !$rv;
}
my ($coef, $fitVals, $r_squared) = poly_fit(
\#XVals,
\#YVals,
$fitorder,
)
or die("Error");
When provided with an input data file, this C program runs successfully, with no error executing PolyFit
lang-C
// PolyFitFileData.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <stdlib.h>
#include "..\PolyFitGSL\PolyFitGSL.h"
#include <time.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
int ReadSingleColDataFile(const char* filename, int numPts, int numHeaderRows, double* data)
{
int i;
double curNum;
char line[32];
FILE* fPtr;
fopen_s(&fPtr, filename, "r");
if (fPtr == NULL)
{
return 1;
}
for (i = 0; i < (numPts + numHeaderRows); i++)
{
if (fgets(line, 32, fPtr) != NULL)
{
if (i >= numHeaderRows)
{
curNum = strtod(line, NULL);
data[i - numHeaderRows] = curNum;
}
}
}
return 0;
}
int main(int argc, char** argv)
{
int i, n, resFit, lineNum;
double* xVals;
double* yVals;
double* coef;
double* estYVals;
double* rSquared;
FILE* fptr;
int fitOrder=1;
if (argc != 5)
{
printf_s("Pass in 4 args: \n(1) number of points \n(2) filename with data (Y values only, one per line, one header line)\n(3) Fit order\n(4) Output Filename (or empty string for none)");
exit(-1);
}
if (fopen_s(&fptr, argv[2], "r") != 0) {
printf("Error! opening input file");
// Program exits if file pointer returns NULL.
exit(-16);
}
n = atoi(argv[1]);
fitOrder = atoi(argv[3]);
xVals = (double*)malloc(n * sizeof(double));
yVals = (double*)malloc(n * sizeof(double));
if (fptr != NULL) {
char line[100];
lineNum = 0;
while ((fgets(line, sizeof line, fptr) != NULL) && lineNum < (n + 1)) /* read a line from a file */ {
if (lineNum > 0)
{
//then parse string and add double to list
yVals[lineNum - 1] = atof(line);
xVals[lineNum - 1] = (double)lineNum;
}
lineNum++;
}
fclose(fptr);
}
else {
return -22;
}
coef = (double*)malloc((fitOrder + 1) * sizeof(double));
estYVals = (double*)malloc(n * sizeof(double));
rSquared = (double*)malloc(sizeof(double));
resFit = PolyFit(n, xVals, yVals, fitOrder, coef, estYVals, rSquared);
//I can print out results to file now here, or to screen....
printf_s("Completed fit. Result from PolyFit function was %d.\n", resFit);
printf_s("Fit order: %d\n", fitOrder);
printf_s("RSquared: %f\n", *rSquared);
printf_s("Coefficients:\n");
for (i = 0; i < fitOrder + 1; i++)
{
printf_s("[x%d] %f\n", i, coef[i]);
}
printf_s("%d Data points (x,y,yFit):\n", n);
for (i = 0; i < n; i++)
{
printf_s("%f\t%f\t%f\n", xVals[i], yVals[i], estYVals[i]);
}
//if you pass in empty string "" then assume that you don't want to write to disk
fptr = NULL;
if (strlen(argv[4]) > 2)
{
if (fopen_s(&fptr, argv[4], "w") != 0) {
printf("Error! opening file for output");
// Program exits if file pointer returns NULL.
exit(-16);
}
fprintf_s(fptr,"Fit order: %d\n", fitOrder);
fprintf_s(fptr, "RSquared: %f\n", *rSquared);
fprintf_s(fptr, "Coefficients:\n");
for (i = 0; i < fitOrder + 1; i++)
{
fprintf_s(fptr, "[x%d] %f\n", i, coef[i]);
}
fprintf_s(fptr, "%d Data points (x,y,yFit):\n", n);
for (i = 0; i < n; i++)
{
fprintf_s(fptr, "%f\t%f\t%f\n", xVals[i], yVals[i], estYVals[i]);
}
fclose(fptr);
}
free(coef);
free(estYVals);
free(rSquared);
free(xVals);
free(yVals);
return 0;
}
This isn't a Perl problem per say; this is about letting Windows know where to find your DLLs. See Dynamic-Link Library Search Order.
The directory in which the script and thus the DLL reside can be obtained using
use FindBin qw( $RealBin );
Among other solution, you'll find switching the current directory to that directory
chdir($RealBin);
and adding it to the PATH
$ENV{PATH} = "$RealBin;$ENV{PATH}";
Related
I am working on a program written in C that recursively walks a given directory in order to print out the Nth largest files and their sizes in bytes. I am using two arrays to account for the filesystem entry names and filesystem entry sizes respectively.
EDIT: I have updated my program to implement the suggestions shared in the comment section. My focus now is on correctly implementing a swap operation within my iSort function.
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
// number of files to display size information for
const int N = 10;
// a struct used to hold filesystem entry names and corresponding sizes in bytes
struct info {
char name[1024];
int size;
};
/* A simple implementation of insertion sort that will operate upon
an array of info structs, sorting them by their member size in
ascending order */
void iSort(struct info *fs_info[], int size, int info_size)
{
int i, j, key;
for (i = 1; i < size; i++)
{
key = fs_info[i]->size;
j = i - 1;
while (j >= 0 && fs_info[j]->size > key)
{
printf("info_size: %d\n", info_size);
// TODO complete a swap operation
memmove(fs_info[j + 1], fs_info[j], info_size);
j = j - 1;
}
fs_info[j + 1]->size = key;
}
}
void get_size(char *path, struct info fs_info[N], int info_size)
{
static int items_added = 0;
static int max_size = 0;
struct stat st;
if (stat(path, &st) == 0)
{
if (items_added < N) // if array capacity will not be exceeded
{
strcpy(fs_info[items_added].name, path);
fs_info[items_added].size = st.st_size;
if (st.st_size > max_size)
max_size = st.st_size;
items_added++;
}
else
{
// do a comparison to determine where to insert
// sort first
iSort(&fs_info, 10, info_size); // this function call results in a seqfault
}
}
else
{
printf("Error getting stat for entry %s: %d\n", path, stat(path, &st));
}
}
void walk(const char *currDir, struct info fs_info[N], int info_size)
{
DIR *dir = opendir(currDir);
struct dirent *entry;
if (dir == NULL)
{
// directory could not be opened
return;
}
while ((entry = readdir(dir)) != NULL)
{
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
{
// if directory is current dir or parent dir
continue;
}
char path_to_entry[1024];
snprintf(path_to_entry, sizeof(path_to_entry), "%s/%s", currDir, entry->d_name);
// use path_to_entry to call stats on the entry
get_size(path_to_entry, fs_info, info_size);
if (entry->d_type == DT_DIR)
{
// recursively visit subdirectories
walk(path_to_entry, fs_info, info_size);
}
}
closedir(dir);
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("Usage: %s <target directory>\n", argv[0]);
}
const char *target_dir = argv[1];
struct info fs_entries[N];
const int info_size = sizeof(struct info);
for (int i = 0; i < N; i++)
{
strcpy(fs_entries[i].name, "");
fs_entries[i].size = 0;
}
printf("Finding %d largest files in: %s\n", N, target_dir);
walk(target_dir, fs_entries, info_size);
for (int i = 0; i < N; i++)
{
printf("%s : %d\n", fs_entries[i].name, fs_entries[i].size);
}
return 0;
}
Currently, the memmove() invocation in iSot() results in a EXC_BAD_ACCESS error, I am working on improving this function now. Any suggestions in the interim are appreciated. Thanks also to those who commented on this question earlier.
This is not so much an answer as it is an example of how one might code this with a bit less fiddling about with every bit/byte.
I don't run a flavour of UNIX, so this offering is untested and may contain typos and even bugs. I hope not.
#include <stdio.h> // From 'generic' to 'specific'
#include <string.h>
#include <sys/stat.h>
#include <dirent.h>
const int N = 10;
// Global array holding names and sizes
struct {
char name[ MAX_PATH ];
size_t size;
} biggies[ N ], wrk; // and a working buffer.
/* "Global" is bad for large projects.
* In this 'utility' program, global saves a LOT of typing/reading.
* Seek clarity, not conformity,
*
* "wrk" is used to buffer ALL paths encountered.
* Notice that each recursion is an EXTENSION of its parent.
* ONE working buffer to deal with.
*/
void walk() {
size_t len = strlen( wrk.name ); // The path so far...
DIR *dir;
if( ( dir = opendir( wrk.name ) ) == NULL )
return;
wrk.name[ len++ ] = '/'; // append a slash ahead of strcpy() below
struct dirent *entry;
while( ( entry = readdir( dir ) ) != NULL ) {
if( strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0 )
continue;
// Notice how each 'local' name is written to "the right spot" in one buffer
strcpy( wrk.name + len, entry->d_name );
if( entry->d_type == DT_DIR ) // directory, so recursion...
walk();
else {
struct stat st;
if( stat( wrk.name, &st ) != 0 ) {
fprintf( stderr, "Error stat'ing '%s'\n", wrk.name );
exit( EXIT_FAILURE );
}
// Add this info to working buffer.
wrk.size = st.st_size;
// Find where to 'insert' this (if it is larger than descending ordered list
for( int i = 0; i < N && biggies[i].size > wrk.size; i++ ) {} // loop
if( i < N ) {
// Slide smaller ones down (don't go out of bounds)
memmove( biggies[i + 1], biggies[i], (N-i-1) * sizeof biggies[0] );
// Copy this one in place.
memcpy( biggies[i], &wrk, sizeof biggies[0] );
}
}
}
closedir(dir);
}
int main( int argc, char *argv[]) {
char *target_dir = argv[1]; // This is okay, so far...
if( argc != 2 ) {
printf( "Usage: %s <target directory>\n", argv[0] );
puts( "Using current directory..." );
target_dir = ".";
}
strcpy( wrk.name, target_dir );
printf( "Finding %d largest files in: %s\n", N, wrk.name );
walk();
for( size_t i = 0; i < N && biggies[i].size != 0; i++ )
printf( "%s : %d\n", biggies[i].name, biggies[i].size);
return 0;
}
You don't need to pass the address of fs_info to iSort() function. fs_info is a pointer to first element of fs_entries array, which is enough to sort the array if the size of array is known. Also, you don't need to pass the size of element of array to iSort().
iSort() function implementation:
void iSort(struct info *fs_info, int size) {
for (int i = 1; i < size; ++i) {
int key = fs_info[i].size;
struct info x = fs_info[i];
int j = i - 1;
while (j >= 0 && fs_info[j].size > key) {
fs_info[j + 1] = fs_info[j];
j--;
}
fs_info[j + 1] = x;
}
}
Use memmove() in iSort():
void iSort (struct info *fs_info, int size) {
for (int i = 1; i < size; ++i) {
int key = fs_info[i].size;
struct info x = fs_info[i];
int j = i - 1;
while (j >= 0 && fs_info[j].size > key) {
j--;
}
if (j != i - 1) {
memmove (&fs_info[j + 2], &fs_info[j + 1], sizeof(*fs_info) * (i - j - 1));
}
memmove (&fs_info[j + 1], &x, sizeof(*fs_info));
}
}
Call iSort() function like this:
iSort(fs_info, N);
There is a lot of scope of improvement in your code, like, it would be good to have array of pointers to struct info instead of array of struct info, so that, during sort simply swapping the pointers required instead of swapping whole structure. Leaving it up to you to identify the improvements and implement them.
I have written a code in C. Inside the for loop in main(), I have written the following. When I run the code, the fprintf statement is not writing the data into the datafile. I am adding edges to a graph. While adding, I am checking whether the pairs are already in the list using adjacent list. If the pairs are not in the list, I am adding the edges, using the function call addEdge():
int main()
{
FILE *ed = NULL;
ed = fopen("c2.txt","w");
FILE *ls = NULL;
ls = fopen("e2.txt", "w");
FILE *lk = NULL;
lk = fopen("link2.txt","w");
if(ls == NULL){
printf("Error in opening file ls!\n");}
if(ed == NULL){
printf("Error in opening file ed!\n");}
if(lk == NULL){
printf("Error in opening file lk!\n");}
else
{
int src,dest;
int src1,dest1;
int i,k,v;
int NV = 500 #No. of nodes
int m = 10000 #No. of edges
int nblinks = 0; # edge counter:
double x[NV],x1[NV];
double x2[NV];
unifRand(x,x1,x2); // function call for infection rate:Pass only name of array:
int ss[NV];
data1(ss); // function call for generated data:
double sum,sum1 = 0.0;
double R = 0.00268; //Learning rate: // (i) 0.01 // ii. 0.001 // (iii) 0.00251 (iv)0.00268
double L[NV][NV-1];
double L1[NV][NV-1];
double L_old[NV][NV-1];
double L2[NV][NV-1];
double t = 0, dt = 0.1;
double C;
struct Graph* graph = createGraph(NV); // Function call for graph:
int d;
int nblinks = 0; // Edge counter:
L_old[0][1] = 0.01; // choice of initial coupling/guess : 0.02
for(i=0; i<NV-1; i++)
{
x2[i] = 0.02;
}
fprintf(ed,"True\t\tMeasured\t x[i]\t\t x1[i]\t\t x2[i]\t\tsum\t\t Error\t\ttime\tnode\n");
fprintf(ed,"------------------------------------------------------------------------------------------------------------\n");
fprintf(lk," Pair of Nodes:\n");
fprintf(lk,"---------------------------------------------------------------------\n");
for( i = 0, k = 1; i < NV-1; i++)
{
struct AdjListNode* temp = graph->array[i].head;
printGraph(graph, &sum, temp);
# if the adjacent node is not zero:
while(temp != NULL && temp->next != NULL)
{
fprintf(ls,"%d %d\n", i, temp->dest);
temp = temp->next;
while(nblinks < m)
{
#Random numbers for source and destination nodes:
int src1 = random()%NV;
int dest1 = random()%NV;
if(src1 < dest1)
{
src = src1;
dest = dest1;
}
else
{
src = dest1;
dest = src1;
}
int pairs[2] = {src, dest};
//If pairs are not in the list, add the edges then:
if(src != dest && pairs[2] != (i, temp->dest))
{
printf("%d\t%d\n",src,dest);
fprintf(lk,"(%d,%d)\t(%d,%d)\n", pairs[0],pairs[1],i, temp->dest);
addEdge(graph, src, dest);
nblinks++; // counter:
} // End if
} //End while1 :
} // End while 2:
# I have written my calculation here :
fprintf(ed,"%0.6lf\t%0.6lf\t%0.6lf\t%0.6lf\t%0.5lf\t\t%0.6lf\t%0.6lf\t%0.1lf\t%d\t%0.6lf\n", L[i][k],L1[0][1],x[i],x1[i],
x2[i],sum1,C, t,ss[k],L2[i][k]);
} // End for
} // End else
fclose(ed);
fclose(ls);
fclose(lk);
ed = NULL;
ls = NULL;
lk = NULL;
return 0;
}
This code is quite strange and some parts of it should not be compiled by c compiler.
E.g.:
int NV = 500 #No. of nodes
int m = 10000 #No. of edges
int nblinks = 0; # edge counter:
where #No. of nodes is like comment and int NV = 500 has no ; in the end - so is not completed line of code.
Style is also not perfect, e.g.:
if(ls == NULL){
printf("Error in opening file ls!\n");}
if(ed == NULL){
printf("Error in opening file ed!\n");}
if(lk == NULL){
printf("Error in opening file lk!\n");}
else
{
should be
if(ls == NULL)
{
printf("Error in opening file ls!\n");
return 1;
}
if(ed == NULL)
{
printf("Error in opening file ed!\n");
return 1;
}
if(lk == NULL)
{
printf("Error in opening file lk!\n");
return 1;
}
// no else needed after 3 way to the exit (return)
or better
if(!lk || !ed || !ls)
{
printf("Error in opening on of the files\n");
return 1;
}
In general, if all files are opened in the required mode (and after all writing are closed) no problem should be with fprintf except incorrect format string or wrong data for output.
UPDATE:
Just to check output, you can use stdout as the first argument of fprintf to see result at the screen (console), or make lk = stdout; instead of lk = fopen("link2.txt", "w");.
Then if you see data at the screen look what is wrong with the file.
I am trying to use MATLAB-API to read .mat file using C (NOT C++).
This is MATLAB code which would create sort of .mat file I want:
A = [[1 2 3]; [5 7 1]; [3 5 9]];
B = [[2 4];[5 7]];
Creator = 'DKumar';
nFilters = 2;
Filters{1} = [[-1.0 -1.0 -1.0]; [-1.0 8 -1.0]; [-1.0 -1.0 -1.0]];
Filters{2} = 2.0*[[-1.0 -1.0 -1.0]; [-1.0 8 -1.0]; [-1.0 -1.0 -1.0]];
cd('/home/dkumar/CPP_ExampleCodes_DKU/Read_mat_File');
save('Test_FILE.mat', 'A', 'B', 'Creator', 'nFilters', 'Filters');
Please notice that I also need to read cell-structure or something similar.
(1) In the C code, it seems that I can read matrix stored in .mat just fine; but, cannot return properly (see the output in the end).
(2) I still have no idea about cell-structure which in this example would STORE DOUBLE MATRICES which may vary in size.
Full-C code follows. First, the function matread, which can seemingly read the data properly.
#include <stdio.h>
#include <stdlib.h>
#include "/usr/local/MATLAB/R2011b/extern/include/mat.h"
struct stDoubleMat{
double* pValueInField;
int nRows, nCols;
};
void matread(const char *file, const char *FieldName2Read, struct stDoubleMat oDoubleMat_LOC)
{
printf("Reading file %s...\n\n", file);
//Open file to get directory
MATFile* pmat = matOpen(file, "r");
if (pmat == NULL) {
printf("Error opening file %s\n", file);
return;
}
// extract the specified variable
mxArray *arr = matGetVariable(pmat, FieldName2Read);
double *pr;
if (arr != NULL && !mxIsEmpty(arr)) {
// copy data
mwSize num = mxGetNumberOfElements(arr);
pr = mxGetPr(arr);
if (pr != NULL) {
oDoubleMat_LOC.pValueInField = pr;
oDoubleMat_LOC.nRows = mxGetM(arr);
oDoubleMat_LOC.nCols = mxGetN(arr);
}
printf("From inside the function \n") ;
printf( "oDoubleMat_LOC.nRows %i ; oDoubleMat_LOC.nCols %i \n", oDoubleMat_LOC.nRows , oDoubleMat_LOC.nCols);
}else{
printf("nothing to read \n") ;
}
// cleanup
mxDestroyArray(arr);
matClose(pmat);
return;
}
In the same file, the main function, which seems to be unable to return the read data:
int main(int argc, char **argv)
{
const char *FileName = "/home/dkumar/CPP_ExampleCodes_DKU/Read_mat_File/Test_FILE.mat";
const char *FieldName2Read = "A";
struct stDoubleMat oDoubleMat;
matread(FileName, FieldName2Read, oDoubleMat);
double* v = oDoubleMat.pValueInField;
printf("From main \n");
printf( "oDoubleMat.nRows %i ; oDoubleMat.nCols %i \n", oDoubleMat.nRows , oDoubleMat.nCols);
/*
for (int i = 0; i < oDoubleMat.nElements; i++)
{
std::cout <<" copied value : " << *v << "\n";
v = v +1;
}*/
return 0;
}
Here is the output
$ gcc -o Test Read_MatFile_DKU_2.c -I/usr/local/MATLAB/R2011b/extern/include -L/usr/local/MATLAB/R2011b/bin/glnxa64 -lmat -lmx
$ ./Test
Reading file /home/dkumar/CPP_ExampleCodes_DKU/Read_mat_File/Test_FILE.mat...
From inside the function
oDoubleMat_LOC.nRows 3 ; oDoubleMat_LOC.nCols 3
From main
oDoubleMat.nRows 0 ; oDoubleMat.nCols 0
Update:
Here is the updated code which read matrix-field just fine. I still have no clue about how to read "cell-structure".
#include <stdio.h>
#include <stdlib.h>
#include "/usr/local/MATLAB/R2011b/extern/include/mat.h"
mxArray *arr;
struct stDoubleMat{
double* pValueInField;
int nRows, nCols;
};
void matread(const char *file, const char *FieldName2Read, struct stDoubleMat* poDoubleMat_LOC)
{
printf("Reading file %s...\n\n", file);
//Open file to get directory
MATFile* pmat = matOpen(file, "r");
if (pmat == NULL) {
printf("Error opening file %s\n", file);
return;
}
// extract the specified variable
arr = matGetVariable(pmat, FieldName2Read);
double *pr;
if (arr != NULL && !mxIsEmpty(arr)) {
// copy data
mwSize num = mxGetNumberOfElements(arr);
pr = mxGetPr(arr);
if (pr != NULL) {
poDoubleMat_LOC->pValueInField = pr;
poDoubleMat_LOC->nRows = mxGetM(arr);
poDoubleMat_LOC->nCols = mxGetN(arr);
}
printf("From inside the function \n") ;
printf( "oDoubleMat_LOC.nRows %i ; oDoubleMat_LOC.nCols %i \n", poDoubleMat_LOC->nRows , poDoubleMat_LOC->nCols);
}else{
printf("nothing to read \n") ;
}
// close the file
matClose(pmat);
return;
}
int main(int argc, char **argv)
{
const char *FileName = "/home/dkumar/CPP_ExampleCodes_DKU/Read_mat_File/Test_FILE.mat";
const char *FieldName2Read = "A";
struct stDoubleMat oDoubleMat;
matread(FileName, FieldName2Read, &oDoubleMat);
double* v = oDoubleMat.pValueInField;
printf("From main \n");
printf( "oDoubleMat.nRows %i ; oDoubleMat.nCols %i \n", oDoubleMat.nRows , oDoubleMat.nCols);
int i;
for (i = 0; i < oDoubleMat.nCols*oDoubleMat.nRows; i++)
{
printf(" copied value : %f \n", *v);
v = v +1;
}
// cleanup the mex-array
mxDestroyArray(arr);
return 0;
}
You pass the "output" argument (oDoubleMat_LOC) by value to matread, so you can never actually get an output because it is copied on input (i.e. only modified locally):
void matread(const char *file, const char *FieldName2Read,
struct stDoubleMat oDoubleMat_LOC) /* oDoubleMat_LOC copied */
Since you are using C, where references are not available, pass a pointer. Redefine matread:
void matread(const char *file, const char *FieldName2Read,
struct stDoubleMat *oDoubleMat_LOC) /* use a pointer */
Then inside matread, you need to dereference it to modify its fields (with -> instead of .):
oDoubleMat_LOC->pValueInField = pr;
oDoubleMat_LOC->nRows = mxGetM(arr);
oDoubleMat_LOC->nCols = mxGetN(arr);
In main, call like this:
struct stDoubleMat oDoubleMat;
matread(FileName, FieldName2Read, &oDoubleMat);
However, note that you have bigger problems because the mxArray that is backing double *pValueInField is both allocate and destroyed inside matread. While you can return the pointer to the data array, it will be a dangling pointer, which points to deallocated data. You'll need to either allocate an mxArray outside of matread and pass it in, or allocate a double * and copy the data into it inside matread. Otherwise, as soon as mxDestroyArray is called, the pointer is useless.
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.
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].