There is a function load that reads an array of structures from a binary file and returns this array.It works correctly.But the problem is that I can not assign an array of structures the value that the load function returns.
struct tickets
{
char plane [7];
char zona [13];
int rate;
int cost;
};
struct tickets* load(char * filename)
{
FILE * file;
char *symbol;
int m = sizeof(int);
int n, i;
int *pti = (int *)malloc(m);
if ((file = fopen(filename, "r")) == NULL)
{
perror("Error occured while opening file");
}
symbol = (char *)pti;
while (m>0)
{
i = getc(file);
if (i == EOF) break;
*symbol = i;
symbol++;
m--;
}
n = *pti;
struct tickets* ptr = (struct tickets *) malloc(n * sizeof(struct tickets));
symbol = (char *)ptr;
while ((i= getc(file))!=EOF)
{
*symbol = i;
symbol++;
}
fclose(file);
return ptr;
}
int main(void)
{
char * filename = "p.dat";
struct tickets* ticket = NULL;
ticket = load(filename);
}
the following proposed code:
cleanly compiles
performs the desired functionality
properly checks for errors
informs the main() function as to how many instances of struct tickets were read
informs the user when any error occurs
cleans up after itself
eliminates one of the calls to malloc()
uses the function: fread() to avoid problems with little/big Endian
documents why each header file is included
assumes the ticket count (first 4 bytes of file) is in binary
incorporates appropriate horizontal and vertical spacing for readability
caveat: since no example input file posted, this code is not tested
and now, the proposed code:
#include <stdio.h> // perror(), NULL, FILE*, EOF,
// fopen(), fclose(), fread()
#include <stdlib.h> // malloc(), free(), exit(), EXIT_FAILURE
#define MAX_PLANE_LEN 7
#define MAX_ZONA_LEN 13
#define COUNT_LEN 4
struct tickets
{
char plane [ MAX_PLANE_LEN ];
char zona [ MAX_ZONA_LEN ];
int rate;
int cost;
};
struct tickets* load( char * filename, size_t * ticketCount )
{
FILE * fp;
if ( ! (fp = fopen( filename, "r" )) )
{
perror( "Error occured while opening file" );
exit( EXIT_FAILURE );
}
size_t bytesRead = fread( ticketCount, 1, COUNT_LEN, fp );
if( bytesRead != COUNT_LEN )
{
fprintf( stderr, "failed to read count of number of instances of 'struct tickets'\n" );
fclose( fp );
exit( EXIT_FAILURE );
}
struct tickets* ptr = malloc( *ticketCount * sizeof( struct tickets ) );
if( ! ptr )
{
perror( "malloc failed" );
fclose( fp );
exit( EXIT_FAILURE );
}
for( size_t i = 0; i < *ticketCount; i++ )
{
size_t numBytes = fread( &(ptr[i]), 1, sizeof( struct tickets ), fp );
if( numBytes != sizeof( struct tickets ) )
{
perror( "read of a struct ticket failed" );
fclose( fp );
free( ptr );
exit( EXIT_FAILURE );
}
}
fclose( fp );
return ptr;
}
int main( void )
{
char * filename = "p.dat";
size_t ticketCount = 0;
struct tickets* ticket = load( filename, &ticketCount );
// ...
free( ticket );
}
Related
I am trying to think of logic on how to read the last line of a file but I cannot come up with answers. ACCOUNTNUM info is a structure. my .dat file who has 3 acc numbers already. Here I want to know how to get the last account number/line which is 2022-3.
This is the function
LastAccountNumber(){
ACCOUNTNUM info;
file = fopen("acctNumbers.dat","r");
char firstAcc[50]="2022-1";//ignore this I was gonna compare this with the last line.
while((fread(&info,sizeof(struct accountNum),1,file))==1){
printf("\nAcc No %s",info.sAccountNum);
}
}
}
This is my structure
struct accountNum{
int sequence;
char sAccountNum[16];
};
typedef struct accountNum ACCOUNTNUM;
Content of my acctNumbers.dat file.
2022-1 ú· 2022-2 ú· 2022-3 ú·
You could call fread in a loop until it returns 0, and then print the last record read:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct accountNum
{
int sequence;
char sAccountNum[16];
} ACCOUNTNUM;
int main( void )
{
FILE *fp;
ACCOUNTNUM info;
bool success = false;
//open file and verify that it is open
fp = fopen( "acctNumbers.dat", "r" );
if ( fp == NULL )
{
fprintf( stderr, "Error opening file!\n" );
exit( EXIT_FAILURE );
}
//skip to last record
while( ( fread( &info, sizeof info, 1, fp) ) == 1 )
{
//set variable to indicate that we have found at
//least one record
success = true;
}
//print last record, if it exists
if ( success )
printf( "Acc No: %s\n", info.sAccountNum );
else
printf( "No records found.\n" );
//cleanup
fclose( fp );
}
However, this is only guaranteed to work if you are sure that the last fread will not perform a partial read, i.e. if you are sure that the file size is an exact multiple of sizeof(ACCOUNTNUM). Because if fread does perform a partial read, then the buffer content will be indeterminate.
If you cannot exclude the possibility of a partial read, then you could use two buffers for reading, and use them alternately:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct accountNum
{
int sequence;
char sAccountNum[16];
} ACCOUNTNUM;
int main( void )
{
FILE *fp;
ACCOUNTNUM info[2];
int current_index = 0;
bool success = false;
size_t ret;
//open file and verify that it is open
fp = fopen( "acctNumbers.dat", "r" );
if ( fp == NULL )
{
fprintf( stderr, "Error opening file!\n" );
exit( EXIT_FAILURE );
}
for (;;) //infinite loop, equivalent to while(1)
{
//read record from file
ret = fread( &info[current_index], sizeof *info, 1, fp);
//swap buffer index
current_index = current_index == 0 ? 1 : 0;
//restart loop if successful
if ( ret == 1 )
{
//set variable to indicate that we have found at
//least one record
success = true;
continue;
}
//break out of loop
break;
}
//print last record, if it exists
if ( success )
printf( "Acc No: %s\n", info[current_index].sAccountNum );
else
printf( "No records found.\n" );
//cleanup
fclose( fp );
}
Or you could use a single buffer and change the way you are calling the function fread, by swapping the second and third function arguments, so that you can detect whether a partial read occurred. If it does occur, you can print an error message and terminate the program.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct accountNum
{
int sequence;
char sAccountNum[16];
} ACCOUNTNUM;
int main( void )
{
FILE *fp;
ACCOUNTNUM info;
bool success = false;
size_t ret;
//open file and verify that it is open
fp = fopen( "acctNumbers.dat", "r" );
if ( fp == NULL )
{
fprintf( stderr, "Error opening file!\n" );
exit( EXIT_FAILURE );
}
//read one record per loop iteration
while ( ( ret = fread( &info, 1, sizeof info, fp) ) != 0 )
{
//verify that no partial read occurred
if ( ret != sizeof info )
{
fprintf( stderr, "Error: Partial read detected!\n" );
exit( EXIT_FAILURE );
}
//set variable to indicate that we have found at
//least one record
success = true;
}
//print last record, if it exists
if ( success )
printf( "Acc No: %s\n", info.sAccountNum );
else
printf( "No records found.\n" );
//cleanup
fclose( fp );
}
You are reading records one by one and storing it in info, it stands to reason that the element ACCOUNTNUM stored in info when the cycle ends is exactly the last record in the file, take the following code which is a slight modification of yours, to illustrate the point:
#include <stdio.h>
struct accountNum {
int sequence;
char sAccountNum[16];
};
typedef struct accountNum ACCOUNTNUM;
int LastAccountNumber(ACCOUNTNUM* info) {
int success = 0;
FILE* file = fopen("acctNumbers.dat", "rb");
if (file == NULL) {
return -1; // Allows you to document different types of errors
}
while ((fread(info, sizeof(struct accountNum), 1, file)) == 1) {
success = 1;
}
fclose(file);
return success;
}
int main() {
ACCOUNTNUM N[] = {{123, "2022-1"}, {111, "2022-2"}, {321, "2022-3"}};
FILE* file = fopen("acctNumbers.dat", "wb");
fwrite(N, 1, sizeof N, file);
fclose(file);
ACCOUNTNUM info;
if (LastAccountNumber(&info) == 1) //if -1 couldn't open file, 0 no record read
printf("\nAcc No %s", info.sAccountNum);
}
Will output:
Acc No 2022-3
Which is exactly the last element in the file.
Live sample: https://onlinegdb.com/q760Ow1vQc
Note that you should verify the return value of fopen to confirm the correct access to the file. Closing the file after you are done with it is also advised.
I have a problem when I try to open a .dat file in a c code. Probably the error I made will be very obvious to some of you but I can't find it so I ask for your help.
The point of my code is to open the .dat file which contains 12.000.000 double numbers and store it in a cuDoubleComplex array which size will be 6.000.000 variables (the even variables of the .dat represents the real part and the odd variables the imaginary (I mean the order, not the value of the variable))
Here is an extract of my code:
#include "cuComplex.h"
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
int main(void)
{
int n = 12000000; //12.000.000
int lse = n / 2;
double *data = (double *)malloc(12000000 * sizeof(double));
double *data2 = (double *)malloc(12000000 * sizeof(double));
FILE *f, *f2;
cuDoubleComplex *se, *se2;
f = fopen("ref_PRI20.dat", "r");
fread(data, sizeof(double), n, f);
fclose(f);
f2 = fopen("surv_PRI20.dat", "r");
fread(data2, sizeof(double), n, f2);
fclose(f2);
for (int a = 0; a < n; a++)
{
printf("%f\n", data2[a]);
}
se = (cuDoubleComplex*)malloc(lse * sizeof(cuDoubleComplex));
se2 = (cuDoubleComplex*)malloc(lse * sizeof(cuDoubleComplex));
for (int a = 0; a<n / 2; a++)
{
se[a].x = data[2 * a];
se[a].y = data[2 * a + 1];
se2[a].x = data2[2 * a];
se2[a].y = data2[2 * a + 1];
}
free(data);
free(data2);
}
I have added the printf lines and bucle just to check and all I get is "0,0000" as a value. Although when I continue with the programm the se and se2 arrays seems to get random values.
I know the size of the arrays is huge but I need to work with that amount of data.
I also have tried to work in matlab and I had no mistakes in there. This is the code that I used in matlab and everything was fine so I guess there is no problem with the .dat files but only with my code.
f = fopen ("ref_PRI20.dat", 'r');
Data = fread (f, 12e6, 'double');
fclose (f);
dat=(Data(1:2:end)+1i*Data(2:2:end)).';
Here's a scan of the input data so you can see the format. I hope it will help.
enter image description here
Any help will be appreciated.
No error checking on the original code for malloc or fopen.
Since a comment said the file was opened in a text reader and had commas between values, fscanf should be used to input the values instead of fread.
Since the values must be scanned one at a time there isn't a need for the data or data2 pointers.
Could not compile this as I don't have cuComplex.h
#include "cuComplex.h"
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
int main(void)
{
int n = 12000000; //12.000.000
int lse = n / 2;
FILE *f, *f2;
cuDoubleComplex *se, *se2;
f = fopen("ref_PRI20.dat", "r");
f2 = fopen("surv_PRI20.dat", "r");
se = malloc(lse * sizeof(cuDoubleComplex));
se2 = malloc(lse * sizeof(cuDoubleComplex));
for (int a = 0; a < lse; a++)
{
if ( 1 != fscanf ( f, "%lf ,", &se[a * 2].x])) {
fprintf ( stderr, "could not scan double\n");
break;
}
if ( 1 != fscanf ( f, "%lf ,", &se[a * 2 + 1].y)) {
fprintf ( stderr, "could not scan double\n");
break;
}
if ( 1 != fscanf ( f2, "%lf ,", &se2[a * 2].x)) {
fprintf ( stderr, "could not scan double\n");
break;
}
if ( 1 != fscanf ( f2, "%lf ,", &se2[a * 2 + 1].y)) {
fprintf ( stderr, "could not scan double\n");
break;
}
}
fclose(f);
fclose(f2);
free ( se);
free ( se2);
return 0;
}
the following proposed code:
cleanly compiles
properly checks for and handles errors
reads the data directly into the struct.
Did not use the cuComplex.h file as that was not available.
avoided the use of 'magic' numbers
although the 'b' is not necessary in linux/unix, properly set the open mode to BINARY READ
documented why each header file is included.
eliminated all unnecessary variables and unnecessary calls to malloc()
eliminated all unnecessary data copying.
It may be desirable to read the data in a loop, using a 'moving window' until a 12000000 doubles are read. I'll let you add that feature, if necessary.
And now the proposed code:
#include <stdio.h> // fopen(), fread(), printf(), fprintf(), perror()
#include <stdlib.h> // exit(), EXIT_FAILURE, malloc(), free()
#define N 12000000
struct cuDoubleComplex
{
double x;
double y;
};
int main(void)
{
struct cuDoubleComplex *data = malloc( (N>>1) * sizeof(double));
if( !data )
{
perror( "malloc failed" );
exit( EXIT_FAILURE );
}
struct cuDoubleComplex *data2 = malloc( (N>>1) * sizeof(double));
if( !data2 )
{
perror( "malloc failed" );
exit( EXIT_FAILURE );
}
FILE *f = fopen("ref_PRI20.dat", "rb");
if( !f )
{
perror( "fopen failed" );
free( data );
free( data2 );
exit( EXIT_FAILURE );
}
size_t nmemb = fread(data, sizeof(double), N, f);
if( nmemb != N )
{
fprintf( stderr, "read of first file only read %lu doubles\n", nmemb );
free( data );
free( data2 );
fclose( f );
exit( EXIT_FAILURE );
}
fclose(f);
FILE *f2 = fopen("surv_PRI20.dat", "rb");
if( !f2 )
{
perror( "fopen failed" );
free( data );
free( data2 );
exit( EXIT_FAILURE );
}
size_t nmemb2 = fread(data2, sizeof(double), N, f2);
if( nmemb2 != N )
{
fprintf( stderr, "read of second file only read %lu doubles\n", nmemb2 );
free( data );
free( data2 );
fclose( f2 );
exit( EXIT_FAILURE );
}
fclose(f2);
for (int a = 0; a < N; a++)
{
printf("%f\n", data2[a].y);
}
free(data);
free(data2);
} // end function: main
I've worked quite a bit with PHP and some with C++ but am brand new to C, as you can tell by my jumbled mess of code. Basically, I'm looking to read the contents of a .txt file (a grid, in this case to make a game for my friends and I) into a 2d array, process the file's contents, and output the processed content into a separate .txt file.
void grab_input(char *infile, int *rows, int *cols, char *buffer);
void send_output(char *outfile, int rows, int cols, char buffer);
int process_input(char *buffer);
int main(int argc, char *argv[])
{
int rows;
int cols;
int i;
char **buffer;
if (argc != 2)
{
printf("Usage: %s filename\n", argv[0]);
exit(EXIT_FAILURE);
}
buffer = (char**)malloc((rows + 2) * sizeof(char *));
for (i = 0; i < rows; i++)
buffer[i] = (char *)malloc(cols*sizeof(char));
grab_input(argv[1], &rows, &cols, &buffer);
process_input(&buffer);
send_output(argv[2], rows, cols, *buffer);
printf("\n%s\n", argv[2]);
printf("%d\n", cols);
return 0;
}
void grab_input(char *infile, int *rows, int *cols, char *buffer)
{
FILE *input;
input = fopen(infile, "r");
if (input != 0)
printf("The file exists.\n");
else
printf("No file.\n");
fscanf(input, "%d %d", rows, cols);
printf("Unprocessed grid:");
while (fgets(buffer, (*rows+2) * (*cols+2) * sizeof(char)+1, input) != NULL) {
printf("%s", buffer);
}
fclose(input);
printf("\nRows: %d\nColumns: %d\n", *rows, *cols);
}
For which I receive several console errors and a "Debug Error... Stack around the variable cols was corrupted." I've done a lot of reading on various sites about dynamic memory allocation, but I'm obviously not quite grasping how to actually put it into practice and make a dynamically-allocated 2D array from a file. If you could help me, it'd be greatly appreciated.
Here's a picture of my console window.
And here's one of the contents of my input.txt file.
Thank you very much for any help.
applying all the comments and cleaning up the logic and performing appropriate error checking results in the following.
The following cleanly compiles.
The following is not tested.
#include <stdio.h> // fgets(), fopen(), fclose(),
// sscanf(), fprintf(), printf()
#include <stdlib.h> // exit(), EXIT_FAILURE
#include <string.h> // memset()
void grab_sizeInfo( FILE *input, size_t *pRow, size_t *pCols );
void grab_input( FILE* fp_in, size_t rows, size_t cols, char **buffer);
void send_output(char *outfile, size_t rows, size_t cols, char **buffer);
void process_input(size_t rows, size_t columns, char **buffer);
int main(int argc, char *argv[])
{
size_t rows = 0;
size_t cols = 0;
char **buffer = NULL;
if (argc != 3)
{
fprintf(stderr, "Usage: %s InputFilename OutputFilename\n", argv[0]);
exit(EXIT_FAILURE);
}
FILE *fp_in = NULL;
if( NULL == (fp_in = fopen( argv[1], "r") ) )
{ // then fopen failed
perror( "fopen for input file failed" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
grab_sizeInfo( fp_in, &rows, &cols );
printf("\nRows: %lu\nColumns: %lu\n", rows, cols);
rows+=2; // adjust for actual size
cols+=2; // adjust for actual size
cols+=1; // +1 to allow for NUL terminator byte
if( NULL == ( buffer = malloc(rows * sizeof(char *)) ) )
{ // then malloc failed
perror( "malloc for array of pointers to rows failed");
fclose( fp_in );
exit( EXIT_FAILURE );
}
// implied else, malloc for array of pointers to rows successful
// prep array of pointers, to make cleanup easy
memset( buffer, '\0', rows * sizeof(char *) );
for ( size_t i = 0; i < rows; i++ )
{
if( NULL == (buffer[i] = malloc(cols) ) )
{ // malloc failed
perror( "malloc for row failed" );
// cleanup
for( size_t j=0; j < rows; j++ )
{
free( buffer[j] );
}
free( buffer );
fclose( fp_in );
exit( EXIT_FAILURE );
}
// implied else, malloc for array of char in row successful
} // end for each row
grab_input( fp_in, rows, cols, buffer);
fclose( fp_in );
process_input(rows, cols, buffer);
send_output(argv[2], rows, cols, buffer);
printf("\n%s\n", argv[2]);
printf("%lu\n", cols);
return 0;
} // end function: main
void grab_sizeInfo( FILE *fp, size_t *pRow, size_t *pCols )
{
char firstLine[20] = {'\0'};
if( fgets( firstLine, sizeof firstLine, fp ) )
{ // successful read
if( 2 != sscanf( firstLine, "%lu %lu", pRow, pCols) )
{ // then sscanf failed
perror( "sscanf for rows and columns failed" );
fclose( fp );
exit(EXIT_FAILURE);
}
}
} // end function: grab_sizeInfo
void grab_input(FILE *fp, size_t rows, size_t cols, char **buffer)
{
size_t rowNum = 0;
while ( rowNum < rows && fgets( buffer[rowNum], (int)cols, fp ) )
{
printf("%s", buffer[rowNum]);
rowNum++;
}
if( rowNum != rows )
{ // then failed to read complete file
fprintf( stderr, "number of rows read: %lu Not equal Number expected rows: %lu\n", rowNum, rows );
for( size_t i=0; i<rows; i++ )
{
free( buffer[i] );
}
free( buffer );
fclose( fp );
exit( EXIT_FAILURE );
}
} // end function: grab_input
I'm trying to build a gym program for a project in college.
We're doing it in C in a Linux environment.
I do not have problems reading from the file, but when I try to update the file, if I print to file with '\n' at the end, it puts double enters between line. And if I don't, it puts all the data in one line.
What should I do?
i.e. I've added an example of a function that reads from the file and one that updates it.
Employees** Init_Gym_emp(Employees** emp, int* num) {
FILE* f = fopen("Gym Employees.txt", "r");
if (f == NULL) {
printf("Failed opening the file. Exiting!\n");
exit(1);
}
char c = '\0';
while (fscanf(f, "%c", &c) == 1) {
if (c == '\n') num[0]++;
}
if (num[0] > 0) num[0]++;
fseek(f, 0, SEEK_SET);
Employees* tmp = (Employees*)malloc(sizeof(Employees));
if (tmp == NULL) {
printf("Memory allocation failed\n");
exit(1);
}
emp = (Employees**)malloc(sizeof(Employees*)*(num[0]));
if (emp == NULL) {
printf("Memory allocation failed\n");
exit(1);
}
int i = 0;
tmp->first_name = (char*)malloc(sizeof(char)* 20);
tmp->last_name = (char*)malloc(sizeof(char)* 20);
tmp->user_name = (char*)malloc(sizeof(char)* 20);
tmp->password = (char*)malloc(sizeof(char)* 20);
tmp->user_type = (char*)malloc(sizeof(char)* 20);
while (fscanf(f, "%20[^#]%*c%20[^#]%*c%ld%*c%20[^#]%*c%10[^#]%*c%20[^#]%*2c", tmp->first_name, tmp->last_name, &tmp->id, tmp->user_name, tmp->password, tmp->user_type) == 6) {
emp[i] = (Employees*)malloc(sizeof(Employees));
if (emp[i] == NULL) {
printf("Memory allocation failed\n");
exit(1);
}
emp[i]->first_name = (char*)malloc(sizeof(char)* (strlen(tmp->first_name) + 1));
emp[i]->last_name = (char*)malloc(sizeof(char)* (strlen(tmp->last_name) + 1));
emp[i]->user_name = (char*)malloc(sizeof(char)* (strlen(tmp->user_name) + 1));
emp[i]->password = (char*)malloc(sizeof(char)* (strlen(tmp->password) + 1));
emp[i]->user_type = (char*)malloc(sizeof(char)* (strlen(tmp->user_type) + 1));
strcpy(emp[i]->first_name, tmp->first_name);
strcpy(emp[i]->last_name, tmp->last_name);
strcpy(emp[i]->user_name, tmp->user_name);
strcpy(emp[i]->password, tmp->password);
strcpy(emp[i]->user_type, tmp->user_type);
emp[i]->id = tmp->id;
i++;
}
free(tmp->first_name);
free(tmp->last_name);
free(tmp->user_name);
free(tmp->password);
free(tmp->user_type);
free(tmp);
fclose(f);
return emp;
}
void update_Gym_emp(Employees** emp, int* num) {
remove("Gym Employees.txt");
FILE* f = fopen("Gym Employees.txt", "w");
if (f == NULL) {
printf("Failed opening the file. Exiting!\n");
exit(1);
}
int i;
for (i = 0; i < num[0]; i++) {
fprintf(f, "%s#%s#%ld#%s#%s#%s#", emp[i]->first_name, emp[i]->last_name, emp[i]->id, emp[i]->user_name, emp[i]->password, emp[i]->user_type);
}
fclose(f);
}
here is one way the code could be written.
Notice that the first function reads from a file and creates a 2D list of Employee records
Notice that the second function writes to that same file from the 2D list of Employee records
Notice the string lengths for the call to fscanf() are one less than the related input buffer size because when scanning a string, the function will always append a NUL byte to the string
Strongly suggest defining the Employee struct as follows rather than the way it is currently defined:
struct Employee
{
char first_name[20];
char last_name[20];
long id;
char user_name[20];
char password[10];
char user_type[20];
};
Now, the proposed code
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Employee
{
char *first_name;
char *last_name;
long id;
char *user_name;
char *password;
char *user_type;
};
typedef struct Employee Employees;
// prototypes
void cleanup( Employees **emp );
Employees** Init_Gym_emp(Employees** emp, int* num)
{
FILE* f = fopen("Gym Employees.txt", "r");
if (f == NULL)
{
perror("fopen for Gym Employees.txt for input failed");
exit(1);
}
// implied else, fopen successful
char buffer[1024]; // input work area
// get count of records in file
while ( fgets(buffer, sizeof(buffer), f) )
{
num[0]++;
}
// step back to beginning of file to read/parse each record
if( fseek(f, 0, SEEK_SET) )
{ // then fseek failed
perror( "fseek to start of file failed" );
fclose( f );
exit( EXIT_FAILURE );
}
// implied else, fseek successful
// allocate array of pointers large enough for all records in input file
if( NULL == (*emp = malloc((size_t)num[0] * sizeof(Employees*) ) ) )
{
perror("malloc for array of pointers to Employee records failed");
cleanup( emp );
fclose( f );
exit(1);
}
// clear all pointers to NULL, to make cleanup easier
memset( *emp, '\0', (size_t)num[0] * sizeof( Employees* ));
char first_name[20];
char last_name[20];
long id;
char user_name[20];
char password[10];
char user_type[20];
int i = 0;
while( i < num[0] && fgets( buffer, sizeof(buffer), f ) )
{
if( 6 != sscanf(buffer,
"%19[^#]# %19[^#]# %ld# %19[^#]# %9[^#]# %19[^#]",
first_name,
last_name,
&id,
user_name,
password,
user_type) )
{ // then sscanf failed
perror( "sscanf for fields of emp record failed" );
cleanup( emp );
fclose( f );
exit( EXIT_FAILURE );
}
// implied else, sscanf successful
// get room for one employee record
if( NULL == (emp[i] = malloc(sizeof(Employees)) ) )
{
perror("malloc for new employee record failed");
cleanup( emp );
fclose( f );
exit( EXIT_FAILURE );
}
// implied else, malloc successful
(*emp)[i].first_name = strdup( first_name );
(*emp)[i].last_name = strdup( last_name );
(*emp)[i].user_name = strdup( user_name );
(*emp)[i].password = strdup( password );
(*emp)[i].user_type = strdup( user_type );
(*emp)[i].id = id;
i++;
} // end while
fclose(f);
return emp;
} // end function: Init_Gym_emp
void update_Gym_emp(Employees** emp, int* num)
{
FILE* f = fopen("Gym Employees.txt", "w");
if (f == NULL)
{
perror("fopen for Gym Employees.txt for write failed");
cleanup( emp );
exit(1);
}
// implied else, fopen successful
for (int i = 0; i < num[0]; i++)
{
fprintf(f, "%s#%s#%ld#%s#%s#%s#",
(*emp)[i].first_name,
(*emp)[i].last_name,
(*emp)[i].id,
(*emp)[i].user_name,
(*emp)[i].password,
(*emp)[i].user_type);
}
fclose(f);
} // end function: update_Gym_emp
#define MAXL 256
I think the problem with my code is that eventho numInput = 3, somehow, output[2] did not exist so that when I try to assign it, the program crash (just guessing).
Is there a way to check if ouput[2] exist? or maybe someone will be able to find out the real problem of my code, that would be awesome!
Any help would be greatly appreciated!
NOTE: The reason that I cast malloc is that it is expected by my lecturer.
Input strings are: 25 7 * 14 - 6 +
1 24 3 + * 41 -
2 37 4 + * 15 +
void processPostfixExp(const char * fileName)
{
char ** input = NULL;
double ** output = NULL;
int i = 0, numInput = 0;
char tempInput[MAXL] = {0};
FILE * pFile = NULL;
/* Get number of strings, check if file is readable and open file */
numInput = checkFile(fileName);
pFile = fopen(fileName, "r");
/* Allocate memory for the string storages and alert if fail */
input = (char**)malloc(numInput * sizeof(char*));
output = (double**)malloc(numInput * sizeof(double*));
if(!input || !output)
{
printf("Memory allocation failed.\n");
system("PAUSE");
exit(1);
}
/* Scan the file by lines and duplicate the string to input storage */
for(i = 0; i < numInput; ++i)
{
fgets(tempInput, MAXL, pFile);
tempInput[strlen(tempInput)-1] = '\0';
input[i] = strdup(tempInput);
//printf("\n%s", input[i]);
}
/* Close file and clear screen */
fclose(pFile);
system("CLS");
/* Call converter and display result */
printf("-------------------------------------------------------\n");
printf("\nPostfix expression evaluation:\n");
for(i = 0; i < numInput; ++i)
{
printf("input = %s", input[i]); /* i = 2 Printf SUCCESS */
*output[i] = evaluatePost(input[i]); /* i = 2 CRASH HERE */
/* I added a check at the top most of the evaluatePost(), program did not get to there */
//printf("\nCase %d: %s\nResult:%.2f\n", i + 1, input[i], *output[i]);
}
printf("\n");
printf("-------------------------------------------------------\n");
}
UPDATE:
so I added these lines and can confirm that output[2] does not exist... how is that possible? Please help, Thank you!
for(i = 0; i < numInput; ++i)
{
*output[i] = (double)i;
printf("output[%d] = %.1f\n", i, *output[i]);
}
The problem is that you have:
*output[i]
You have allocated numInput pointers to double, but the pointers themselves don't exist.
It looks like you want to allocate space not for pointers, but for doubles:
double *output;
…
output = (double*)malloc(numInput * sizeof(double));
I'm not sure what is wrong with your call to evaluatePost(), especially as you have not provided a prototype for that function.
However, overall, your code should look similar to the following:
in the future, please post code that (standalone) actually cleanly compiles
when you want help with a run time problem.
strongly suggest compiling with all warnings enabled.
For gcc, at a minimum, use '-Wall -Wextra -pedantic'
When handling a error, always cleanup allocated memory, open files, etc.
#define _POSIX_C_SOURCE (200809L)
#include <stdio.h>
#include <stdlib.h> // exit() and EXIT_FAILURE
#include <string.h> // memset() and strdup()
#define MAXL (256)
// prototypes
int checkFile( const char * );
double evaluatePost( char * );
void processPostfixExp(const char * fileName)
{
char **input = NULL;
double **output = NULL;
int i = 0;
int numInput = 0;
char tempInput[MAXL] = {0};
FILE *pFile = NULL;
/* Get number of strings, check if file is readable and open file */
numInput = checkFile(fileName);
if( NULL == (pFile = fopen(fileName, "r") ) )
{ // then fopen failed
perror( "fopen for input file failed" );
exit( EXIT_FAILURE );
}
/* Allocate memory for the string storages and alert if fail */
if( NULL == (input = malloc(numInput * sizeof(char*)) ) )
{ // then malloc failed
perror( "malloc for input failed" );
fclose( pFile );
exit( EXIT_FAILURE );
}
// implied else, malloc successful
memset( input, 0x00, numInput*sizeof(char*) ); // to make later free() operation easy
if( NULL == (output = malloc(numInput * sizeof(double*)) ) )
{ // then malloc failed
perror( "malloc for output failed" );
fclose( pFile );
free( input );
exit( EXIT_FAILURE );
}
// implied else, malloc successful
memset( output, 0x00, numInput * sizeof(double*) ); // to make later free() operation easy
/* Scan the file by lines and duplicate the string to input storage */
for(i = 0; i < numInput; ++i)
{
if( NULL == fgets(tempInput, MAXL, pFile) )
{ // then fgets failed
perror( "fgets for input file failed" );
fclose( pFile );
for( int j=0; j<numInput; j++ )
{
free( input[j] );
free( output[j] );
}
free( input );
free( output );
exit( EXIT_FAILURE );
}
// implied else, fgets successful
char * offset = NULL;
if( NULL != (offset = strstr( tempInput, "\n" )) )
{ // then newline found
*offset = '\0';
}
if( NULL == (input[i] = strdup(tempInput) ) )
{ // then strdup failed
perror( "strdup for input line failed" );
fclose( pFile );
for( int j=0; j<numInput; j++ )
{
free( input[j] );
free( output[j] );
}
free( input );
free( output );
exit( EXIT_FAILURE );
}
//printf("\n%s", input[i]);
} // end for
/* Close file and clear screen */
fclose(pFile);
system("CLS");
/* Call converter and display result */
printf("-------------------------------------------------------\n");
printf("\nPostfix expression evaluation:\n");
for(i = 0; i < numInput; ++i)
{
printf("input = %s", input[i]); /* i = 2 Printf SUCCESS */
*output[i] = evaluatePost(input[i]); /* i = 2 CRASH HERE */
/* I added a check at the top most of the evaluatePost(), program did not get to there */
//printf("\nCase %d: %s\nResult:%.2f\n", i + 1, input[i], *output[i]);
}
printf("\n");
printf("-------------------------------------------------------\n");
for( int j=0; j<numInput; j++ )
{
free( input[j] );
free( output[j] );
}
free( input );
free( output );
} // end function: processPostfixExp