Confusing about fread , fseek exact operation - c

C code:
Part of code 1:
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <stdio.h>
#define READONLY "r"
#define UPDATE "r+"
#define FALSE 0
#define TRUE 1
typedef int Boolean;
# define ERROR -1
typedef struct {
int identification ;
char name[NAMESIZE] ;
char subject[SUBJECTSIZE] ;
int grade ;
} RECORD ;
typedef struct {
char type ;
RECORD student ;
} TRANSACTION ;
typedef struct {
char occupied ;
RECORD student ;
} MASTER ;
Part of code 2 :
void main(int argc, char *argv[])
{
FILE *fpmas,*fptrans ;
int current_key ,
relative_record_number ;
boolean allocated;
TRANSACTION transaction;
MASTER master ;
clrscr();
prog = argv[0];
Part of code 3 :
int read_master_record(FILE *fp,
int relative_record_number, MASTER *master)
{
if(fseek(fp, (long) relative_record_number
*sizeof(MASTER), SEEK_SET) !=0 )
return(ERROR) ;
else if(fread((char *)master, sizeof(MASTER), 1, fp) != 1)
return(ERROR) ;
else
return(relative_record_number) ;
}
I am confused about the red mark areas(In image file I attached!) , (char *),!=0 and !=1, respectively in *sizeof(MASTER), SEEK_SET) !=0 ) and else if(fread((char *)master, sizeof(MASTER), 1, fp) != 1). What does they meaning?! I search on those but found nothing. Can anyone present any documents on these topics or any explain?!
Question on Red Marks!

First, let's break those parts down in English. Then, we can determine a meaning.
The first one:
if(fseek(fp, (long) relative_record_number
*sizeof(MASTER), SEEK_SET) !=0 )
English: Return error if the return code of fseek is not 0. The return value of fseek is 0 on success. Therefor, != 0 = failure.
The second statement:
else if(fread((char *)master, sizeof(MASTER), 1, fp) != 1)
The cast is unnecessary and more for documentation. It is always safe to cast any pointer to char*. This is sort of a way to say "I'm sending this structure as raw bytes."
English: Return error if the return value of fread is not 1. The return value of fread:
On success, fread() and fwrite() return the number of items read
or written. This number equals the number of bytes transferred
only when size is 1. If an error occurs, or the end of the file
is reached, the return value is a short item count (or zero).
Here, we are checking if the return value != 1. Therefor we are checking to if fread read exactly 1 item.

Related

DES CBC mode not outputting correctly

I am working on a project in C to implement CBC mode on top of a skeleton code for DES with OpenSSL. We are not allowed to use a function that does the CBC mode automatically, in the sense that we must implement it ourselves. I am getting output but I have result files and my output is not matching up completely with the intended results. I also am stuck on figuring out how to pad the file to ensure all the blocks are of equal size, which is probably one of the reasons why I'm not receiving the correct output. Any help would be appreciated. Here's my modification of the skeleton code so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/des.h>
#include <sys/time.h>
#include <unistd.h>
#define ENC 1
#define DEC 0
DES_key_schedule key;
int append(char*s, size_t size, char c) {
if(strlen(s) + 1 >= size) {
return 1;
}
int len = strlen(s);
s[len] = c;
s[len+1] = '\0';
return 0;
}
int getSize (char * s) {
char * t;
for (t = s; *t != '\0'; t++)
;
return t - s;
}
void strToHex(const_DES_cblock input, unsigned char *output) {
int arSize = 8;
unsigned int byte;
for(int i=0; i<arSize; i++) {
if(sscanf(input, "%2x", &byte) != 1) {
break;
}
output[i] = byte;
input += 2;
}
}
void doBitwiseXor(DES_LONG *xorValue, DES_LONG* data, const_DES_cblock roundOutput) {
DES_LONG temp[2];
memcpy(temp, roundOutput, 8*sizeof(unsigned char));
for(int i=0; i<2; i++) {
xorValue[i] = temp[i] ^ data[i];
}
}
void doCBCenc(DES_LONG *data, const_DES_cblock roundOutput, FILE *outFile) {
DES_LONG in[2];
doBitwiseXor(in, data, roundOutput);
DES_encrypt1(in,&key,ENC);
printf("ENCRYPTED\n");
printvalueOfDES_LONG(in);
printf("%s","\n");
fwrite(in, 8, 1, outFile);
memcpy(roundOutput, in, 2*sizeof(DES_LONG));
}
int main(int argc, char** argv)
{
const_DES_cblock cbc_key = {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef};
const_DES_cblock IV = {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef};
// Initialize the timing function
struct timeval start, end;
gettimeofday(&start, NULL);
int l;
if ((l = DES_set_key_checked(&cbc_key,&key)) != 0)
printf("\nkey error\n");
FILE *inpFile;
FILE *outFile;
inpFile = fopen("test.txt", "r");
outFile = fopen("test_results.txt", "wb");
if(inpFile && outFile) {
unsigned char ch;
// A char array that will hold all 8 ch values.
// each ch value is appended to this.
unsigned char eight_bits[8];
// counter for the loop that ensures that only 8 chars are done at a time.
int count = 0;
while(!feof(inpFile)) {
// read in a character
ch = fgetc(inpFile);
// print the character
printf("%c",ch);
// append the character to eight_bits
append(eight_bits,1,ch);
// increment the count so that we only go to 8.
count++;
const_DES_cblock roundOutput;
// When count gets to 8
if(count == 8) {
// for formatting
printf("%s","\n");
// Encrypt the eight characters and store them back in the char array.
//DES_encrypt1(eight_bits,&key,ENC);
doCBCenc(eight_bits, roundOutput, outFile);
// prints out the encrypted string
int k;
for(k = 0; k < getSize(eight_bits); k++){
printf("%c", eight_bits[k]);
}
// Sets count back to 0 so that we can do another 8 characters.
count = 0;
// so we just do the first 8. When everything works REMOVE THE BREAK.
//break;
}
}
} else {
printf("Error in opening file\n");
}
fclose(inpFile);
fclose(outFile);
// End the timing
gettimeofday(&end, NULL);
// Initialize seconds and micros to hold values for the time output
long seconds = (end.tv_sec - start.tv_sec);
long micros = ((seconds * 1000000) + end.tv_usec) - (start.tv_usec);
// Output the time
printf("The elapsed time is %d seconds and %d microseconds\n", seconds, micros);
}
Your crypto is at least half correct, but you have a lot of actual or potential other errors.
As you identified, raw CBC mode can only encrypt data which is a multiple of the block size, for DES 64 bits or 8 bytes (on most modern computers and all where you could use OpenSSL). In some applications this is okay; for example if the data is (always) an MD5 or SHA-256 or SHA-512 hash, or a GUID, or an IPv6 (binary) address, then it is a block multiple. But most applications want to handle at least any length in bytes, so they need to use some scheme to pad on encrypt and unpad on decrypt the last block (all blocks before the last already have the correct size). Many different schemes have been developed for this, so you need to know which to use. I assume this is a school assignment (since no real customer would set such a stupid and wasteful combination of requirements) and this should either have been specified or clearly left as a choice. One padding scheme very common today (although not for single-DES, because that is broken, unsafe, obsolete, and not common) is the one defined by PKCS5 and generalized by PKCS7 and variously called PKCS5, PKCS7, or PKCS5/7 padding, so I used that as an example.
Other than that:
you try to test feof(inpFile) before doing fgetc(inpFile). This doesn't work in C. It results in your code treating the low 8 bits of EOF (255 aka 0xFF on practically all implementations) as a valid data character added to the characters that were actually in the file. The common idiom is to store the return of getchar/getc/fgetc in a signed int and compare to EOF, but that would have required more changes so I used an alternate.
you don't initialize eight_bits which is a local-scope automatic duration variable, so its contents are undefined and depending on the implementation are often garbage, which means trying to 'append' to it by using strlen() to look for the end won't work right and might even crash. Although on some implementations at least some times it might happen to contain zero bytes, and 'work'. In addition it is possible in C for a byte read from a file (and stored here) to be \0 which will also make this work wrong, although if this file contains text, as its name suggests, it probably doesn't contain any \0 bytes.
once you fill eight_bits you write 'off-the-end' into element [8] which doesn't exist. Technically this is Undefined Behavior and anything at all can happen, traditionally expressed on Usenet as nasal demons. Plus after main finishes the first block it doesn't change anything in eight_bits so all further calls to append find it full and discard the new character.
while you could fix the above points separately, a much simple solution is available: you are already using count to count the number of bytes in the current block, so just use it as the subscript.
roundOutput is also an uninitialized local/auto variable within the loop, which is then used as the previous block for the CBC step, possibly with garbage or wrong value(s). And you don't use the IV at all, as is needed. You should allocate this before the loop (so it retains its value through all iterations) and initialize it to the IV, and then for each block in the loop your doCBCenc can properly XOR it to the new block and then leave the encrypted new block to be used next time.
your code labelled 'prints out the encrypted string' prints plaintext not ciphertext -- which is binary and shouldn't be printed directly anyway -- and is not needed because your file-read loop already echoes each character read. But if you do want to print a (validly null-terminated) string it's easier to just use fputs(s) or [f]printf([f,]"%s",s) or even fwrite(s,1,strlen(s),f).
your doCBCenc has a reference to printvalueofDES_LONG which isn't defined anywhere, and which along with two surrounding printf is clearly not needed.
you should use a cast to convert the first argument to doCBCenc -- this isn't strictly required but is good style and a good compiler (like mine) complains if you don't
finally, when an error occurs you usually print a message but then continue running, which will never work right and may produce symptoms that disguise the problem and make it hard to fix.
The below code fixes the above except that last (which would have been more work for less benefit) plus I removed routines that are now superfluous, and the timing code which is just silly: Unix already has builtin tools to measure and display process time more easily and reliably than writing code. Code I 'removed' is under #if 0 for reference, and code I added under #else or #if 1 except for the cast. The logic for PKCS5/7 padding is under #if MAYBE so it can be either selected or not. Some consider it better style to use sizeof(DES_block) or define a macro instead of the magic 8's, but I didn't bother -- especially since it would have required changes that aren't really necessary.
// SO70209636
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/des.h>
#include <sys/time.h>
#include <unistd.h>
#define ENC 1
#define DEC 0
DES_key_schedule key;
#if 0
int append(char*s, size_t size, char c) {
if(strlen(s) + 1 >= size) {
return 1;
}
int len = strlen(s);
s[len] = c;
s[len+1] = '\0';
return 0;
}
int getSize (char * s) {
char * t;
for (t = s; *t != '\0'; t++)
;
return t - s;
}
void strToHex(const_DES_cblock input, unsigned char *output) {
int arSize = 8;
unsigned int byte;
for(int i=0; i<arSize; i++) {
if(sscanf(input, "%2x", &byte) != 1) {
break;
}
output[i] = byte;
input += 2;
}
}
#endif
void doBitwiseXor(DES_LONG *xorValue, DES_LONG* data, const_DES_cblock roundOutput) {
DES_LONG temp[2];
memcpy(temp, roundOutput, 8*sizeof(unsigned char));
for(int i=0; i<2; i++) {
xorValue[i] = temp[i] ^ data[i];
}
}
void doCBCenc(DES_LONG *data, const_DES_cblock roundOutput, FILE *outFile) {
DES_LONG in[2];
doBitwiseXor(in, data, roundOutput);
DES_encrypt1(in,&key,ENC);
#if 0
printf("ENCRYPTED\n");
printvalueOfDES_LONG(in);
printf("%s","\n");
#endif
fwrite(in, 8, 1, outFile);
memcpy(roundOutput, in, 2*sizeof(DES_LONG));
}
int main(int argc, char** argv)
{
const_DES_cblock cbc_key = {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef};
const_DES_cblock IV = {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef};
#if 0
// Initialize the timing function
struct timeval start, end;
gettimeofday(&start, NULL);
#endif
int l;
if ((l = DES_set_key_checked(&cbc_key,&key)) != 0)
printf("\nkey error\n");
#if 1
DES_cblock roundOutput; // must be outside the loop
memcpy (roundOutput, IV, 8); // and initialized
#endif
FILE *inpFile;
FILE *outFile;
inpFile = fopen("test.txt", "r");
outFile = fopen("test.encrypt", "wb");
if(inpFile && outFile) {
unsigned char ch;
// A char array that will hold all 8 ch values.
// each ch value is appended to this.
unsigned char eight_bits[8];
// counter for the loop that ensures that only 8 chars are done at a time.
int count = 0;
#if 0
while(!feof(inpFile)) {
// read in a character
ch = fgetc(inpFile);
#else
while( ch = fgetc(inpFile), !feof(inpFile) ){
#endif
// print the character
printf("%c",ch);
#if 0
// append the character to eight_bits
append(eight_bits,1,ch);
// increment the count so that we only go to 8.
count++;
#else
eight_bits[count++] = ch;
#endif
#if 0
const_DES_cblock roundOutput;
#endif
// When count gets to 8
if(count == 8) {
// for formatting
printf("%s","\n");
// Encrypt the eight characters and store them back in the char array.
//DES_encrypt1(eight_bits,&key,ENC);
doCBCenc((DES_LONG*)eight_bits, roundOutput, outFile);
#if 0
// prints out the encrypted string
int k;
for(k = 0; k < getSize(eight_bits); k++){
printf("%c", eight_bits[k]);
}
#endif
// Sets count back to 0 so that we can do another 8 characters.
count = 0;
// so we just do the first 8. When everything works REMOVE THE BREAK.
//break;
}
}
#if MAYBE
memset (eight_bits+count, 8-count, 8-count); // PKCS5/7 padding
doCBCenc((DES_LONG*)eight_bits, roundOutput, outFile);
#endif
} else {
printf("Error in opening file\n");
}
fclose(inpFile);
fclose(outFile);
#if 0
// End the timing
gettimeofday(&end, NULL);
// Initialize seconds and micros to hold values for the time output
long seconds = (end.tv_sec - start.tv_sec);
long micros = ((seconds * 1000000) + end.tv_usec) - (start.tv_usec);
// Output the time
printf("The elapsed time is %d seconds and %d microseconds\n", seconds, micros);
#endif
}
PS: personally I wouldn't put the fwrite in doCBCenc; I would only do the encryption and let the caller do whatever I/O is appropriate which might in some cases not be fwrite. But what you have is not wrong for the requirements you apparently have.

Read from a csv file , separate every line and every field in C

I have a csv file in which I have to separate every line (\n) and every field (,) in this line.
My goal is to create an array of structs. Every struct in each "box" of the array must contains 4 fields of every line.
How can I write it in c?
I thought to use fscanf and fgets but I don't know how to use them together because with fgets I want to divide lines while with fscanf i want to divide fields .
Final situation :
| 0 , noto, 233460, 32209.073312 | 1, piangea, 4741192, 811.. | 2 ,spenti! , .... |
| position 0 in the array | position 1 in the array | position 2 in the array |
records.csv
0,noto,233460,32209.073312
1,piangea,4741192,81176.622633
2,spenti!,1014671, 4476.013614
3,misericordia,496325,61628.929334
4,quando,4476757,10838.641053
main.c
#include <stdlib.h>
#include<stdio.h>
#include <string.h>
struct _SortedArray {
int id;
char field1[12];
int field2;
float field3;
};
int main() {
FILE *fd;
int res;
struct _SortedArray files[101];
int n;
fd = fopen("records.csv", "r");
if (fd == NULL) {
perror("Error");
exit(1);
}
char r[100];
n = 0;
while (n<6) {
if(fgets(r,100,fd)!=NULL){
puts(r);
fscanf(r, "%[^,],%[^,],%[^,],%[^\n]\n", &files[n].id, &files[n].field1, &files[n].field2, &files[n].field3);
}
n++;
}
for(int i=0;i<6;i++){
printf(" INT:%c,CHAR:%s //",files[i].id, files[i].field1);
}
return 0;
}
Your code contains various little problems and a major inconsistency. The major inconsistency is that you should use sscanf instead of fscanf to process the line returned by fgets.
But that is not all:
misericordia has 12 characters. As C strings require a NULL terminator, field1 must have at least 13 as size
the format characters should be consistent with the type of the fields
when you read into a char array, the array decays to a pointer: you must not add th &
So the line could become:
sscanf(r, "%d,%[^,],%d,%f", &files[n].id, files[n].field1, &files[n].field2, &files[n].field3)
Other possible improvements:
identifiers starting with _ should be reserved for those that you do not use. Close to an opinion, but here you should better use SortedArray
replace plain magic values for sizes with the sizeof operator where you can. If you later change a size, you will have to change it in one single place in your code (best practice: Don't Repeat Yourself)
control the result of input functions (here [s]scanf to be robust against erroneous input data
eventually control that nothing is left at the end of line
only try to print as many lines as you could read
remove unused variables (a nice compiler should emit warnings)
always limit input of string to the size of the buffer (%12[^,])
The code could become:
#include <stdlib.h>
#include<stdio.h>
#include <string.h>
struct SortedArray {
int id;
char field1[13];
int field2;
float field3;
};
int main() {
FILE *fd;
// int res;
struct SortedArray files[101];
int n;
fd = fopen("records.csv", "r");
if (fd == NULL) {
perror("Error");
exit(1);
}
char r[100];
for (n=0; n<sizeof(files)/sizeof(files[0]); n++) {
if(fgets(r,sizeof(r),fd)==NULL){
break;
}
char dummy[2]; // to control nothing is left on end of line
//puts(r);
if (4 != sscanf(r, "%d,%12[^,],%d,%f%1s", &files[n].id, files[n].field1, &files[n].field2, &files[n].field3, dummy)) {
perror("Incorrect line");
fprintf(stderr, "Line %d : %s\n", n+1, r);
}
}
for(int i=0;i<n;i++){
printf(" INT:%d,CHAR:%s //",files[i].id, files[i].field1);
}
return 0;
}

Dynamical Allocation & Structs - allocating memory dinamically to a string from a struct

I've got a problem regarding Dynamical Allocation & Structs.
The task: I have a struct of students, which looks like that:
typedef struct{
unsigned id;
char *lastName;
float grade;
}students_t;
I'm not allowed to pass to lastName a maximum number of characters, it must remain a pointer which size I will increase every time.
My code looks like this:
unsigned counter = 0;
students_t* students = NULL;
students_t temp;
char char_current;
unsigned char_counter=0;
while (fscanf(inputFile,"%u",&temp.id) == 1) {
students = realloc(students,(counter+1) * sizeof(students_t));
students[counter].id=temp.id;
printf("%d",students[counter].id);
students[counter].lastName = NULL;
while (fscanf(inputFile,"%c",&char_current) != ' ') {
students[counter].lastName = realloc(students[counter].lastName,(char_counter+1) * sizeof(char));
students[counter].lastName[char_counter] = char_current;
char_counter++;
}
students[counter].lastName[char_counter] = '\0';
fscanf(inputFile,"%f",&students[counter].grade);
counter++;
}
My problem is with the fscanf from the while (because the program enters an infinite loop), but I don't know how to actually fix it.
I would be grateful if someone could help me figure it out.
Thank you!
You have several problems:
The while() loop isn't terminating (your initial question).
fscanf() is unsafe - there are better alternatives.
You're using fscanf() incorrectly.
Reading a string a character at a time is inefficient.
Repeatedly calling "realloc()" is inefficient - there are better alternatives.
Here is some example code.
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#define MAX_STRING 80
typedef struct {
unsigned id;
char *lastName;
float grade;
} students_t;
students_t* enter_new_student (FILE *inputFile)
{
char buffer[MAX_STRING];
unsigned id;
int iret;
// Check for end of input
iret = fscanf(inputFile, "%u", &id);
if ((iret < 1) || feof(inputFile)) { // iret should be "1" if successful
return NULL;
}
// Allocate a record and read its data
students_t *student = (students_t *)malloc(sizeof(students_t));
iret = fscanf(inputFile, "%s %f", buffer, &student->grade); // iret should be "2" if successful
student->id = id;
student->lastName = strdup(buffer); // strdup() does an implicit "malloc()" and "strcpy()"
// Return new student
return student;
}
int main()
{
students_t *student = NULL;
int record_counter = 0;
FILE *fp;
// Open file
if (!(fp = fopen("tmp.txt", "r"))) {
perror("unable to open file");
return 1;
}
// Read student records
while ((student = enter_new_student(fp))) {
if (student) {
++record_counter;
printf("new student=%s,id=%u, grade=%f, record_counter=%d\n",
student->lastName, student->id, student->grade, record_counter);
}
}
// Done
printf("Done: final record count=%d\n", record_counter);
return 0;
}
Here is a sample "tmp.txt" file:
1 Johnson 4.0
2 Jackson 3.5
3 Jamison 3.85
And corresponding sample output:
new student=Johnson,id=1, grade=4.000000, record_counter=1
new student=Jackson,id=2, grade=3.500000, record_counter=2
new student=Jamison,id=3, grade=3.850000, record_counter=3
In general, prefer using fgets() over fscanf(): Disadvantages of scanf
Notice that I put everything having to do with reading a student record inside a separate function: enter_new_student(). You'll also notice that the "control structure" - the "while loop" is OUTSIDE of the function.
There are two (related) conditions that can cause the loop to exit:
Didn't read "id"
End of file
The reason your original "while loop" failed was that fscanf() will never return ' ' ... so you inadvertently coded an "infinite loop". Here's why:
https://linux.die.net/man/3/fscanf
Return Value
These functions return the number of input items successfully matched and assigned, which can be fewer than provided
for, or even zero in the event of an early matching failure.
The value EOF is returned if the end of input is reached before either
the first successful conversion or a matching failure occurs. EOF is
also returned if a read error occurs, in which case the error
indicator for the stream (see ferror(3)) is set, and errno is set
indicate the error.

gdb debugging - only \n inside stdin

I'm debugging my program in windows with GDB and need stdin.
So, I compiled it :
gcc -g abstieg2.c
gdb a
break 1
run < graph1.in
But the stdin has only \n in it!
do{
getline(&line,&size,stdin);
} while(!strcmp("\n",line)); // for testing, gets stuck forever, but only with gdb
I really can't see what more can be relevant to this problem.
Thanks
stripped down version of my code:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <limits.h>
void *errorchecked_malloc(unsigned int);
unsigned int correctinput(char**);
void free_us();
void my_qsort(int , int r);
unsigned int *Dijkstra(int , int , unsigned int , int );
unsigned int min_distance(unsigned int* , int );
int linearsearch(int);
char* strerror(int);
unsigned int *start_edge=NULL; // Input of edges is organised into three array
unsigned int *end_edge=NULL;
unsigned int *length_edge=NULL;
unsigned int *base_camp=NULL ; // Input of basecamps
unsigned int *Dijkstra_dist=NULL; // distance value of dijkstra algorithm
unsigned int *Dijkstra_vis=NULL; // visited by dijkstra algorithm?
unsigned int *Dijkstra_predec=NULL ; // predecessor of dijkstra algorithm
unsigned int* found=NULL;
int * pos_in_vertices;
char* store_for_reset= NULL; // line (input) char* wil be changed, in store_for_reset line will be saved
int basecamp_length=0;
/*Aim: Find the shortest way in a graph from start_vertices to finish_vertices
* restrictions:
* -2 Day travel with max_distance per day
* -after one day a basecamp must be reached( or the finish vertices)
* -N vertices <=N
*
* Input is organized as following:
* start_vertices finish_vertices d_max\n //
* start_vertices end_vertices max_distance\n // for each edge
* ...
* base_camp\n
* base_camp\n
* ...
*/
int main( ) {
int N=0; // count of vertices
int arg_line_count=0; //
unsigned int start; // First three Input of start basecamp
unsigned int end; // finish basecamp
unsigned int d_max; // maximum travel distance per day
char* line = (char *)errorchecked_malloc(36*sizeof(char));
store_for_reset= line;
int size =strlen(line);
//Input configuration
do{
getline(&line,&size,stdin);
printf("%s",line);
} while(!strcmp("\n",line));// for testing, gets stuck forever, but only with gdb
start_edge = (int*)errorchecked_malloc(sizeof(int)*1000); // creating space, TODO dynamic space allocation
end_edge = (int*)errorchecked_malloc(sizeof(int)*1000);
length_edge = (int*)errorchecked_malloc(sizeof(int)*1000);
start = correctinput(&line); // first line input
end = correctinput(&line);
d_max = correctinput(&line);
// input of all edges
for(int i=0;fgets(line,size,stdin);i++){ // fgets returns NULL if stdin empty
printf("Zeile %d \n", i);
start_edge[i]=correctinput(&line);
printf("line: %s", line);
if(line[0]=='\0'){ // end of line, means now are only basecamps left
base_camp[0]=start_edge[i];
start_edge[i]=0;
basecamp_length=1;
break;
}
if(start_edge[i]>N) N= start_edge[i];
end_edge[i]=correctinput(&line);
length_edge[i]=correctinput(&line);
line =store_for_reset;
}
// Input of basecamps
base_camp= (int*)errorchecked_malloc(sizeof(int)*N); // generous, N is maximum of Nodes
for(int i=1;fgets(line,size,stdin);i++){
base_camp[i]=correctinput(&line);
if(line!=NULL){
printf("fatal error:Too many arguments per line while reading \"Basislagern\" input");
free_us();
exit(-1);
}
basecamp_length++;
}
free_us();
}
unsigned int correctinput( char** string){
char* test;
unsigned int tmp =strtol(*string,&test,10);
if((test[0]!=' ' && test[0]!= '\n' ) || errno != 0 ) {
printf("Don't mock me! Please use the correct input format. \n Information: ");
strerror(errno);
printf(" Next Character: \'%d\'", atoi(test));
free_us();
exit(-1);
}
//printf("test: %s, /n",test);
int i;
for(i=0;(*string)[i]>='0' && (*string)[i]<='9';i++){
*string=(*string)+ i*sizeof(char); // moves the input pointer to the next argument( therefore pointer to pointer)
}
if(*string[i]==' ')string++;
return tmp;
}
void free_us(){
free(start_edge);
free(end_edge);
free(length_edge);
free(base_camp);
free(Dijkstra_dist);
free(Dijkstra_vis);
free(pos_in_vertices);
free(Dijkstra_predec);
free(store_for_reset);
free(found);
}
void *errorchecked_malloc(unsigned int size){
void *ptr;
ptr = malloc(size);
if(ptr == NULL) {
fprintf(stderr, "Error: could not allocate heap memory. \n");
free_us();
exit(-1);
}
return ptr;
}
Input looks like this:
0 1 3924456639
0 5 1268156980
0 18 293858388
0 74 142402607
1 4 145988610
....
24
1
27
79
4
70
...
You are probably hitting this Windows specific gdb bug:
https://www.cygwin.com/ml/cygwin/1999-04/msg00308.html
Try to upgrade to a latest version of gdb (8.0 as of now).
Among other things there were some enhancements for debugging on MS-Windows in this release. See in NEWS file:
55 * Native debugging on MS-Windows supports command-line redirection
56
57 Command-line arguments used for starting programs on MS-Windows can
58 now include redirection symbols supported by native Windows shells,
59 such as '<', '>', '>>', '2>&1', etc. This affects GDB commands such
60 as "run", "start", and "set args", as well as the corresponding MI
61 features.

This algorithm doesn't work

I've created a binary file with three persons (Code-Name-Sex) when I write the data into the file and then I read them, it work perfectly so..
I want that the next function read all the information of the X person have (if it exist).
Syntax:
#include <stdio.h>
struct alu{
int cod;
char name[30]; //alu[0]="juan" alu[1]="pedro" alu[2]="leo"
int sex;
};
int FSearch(char path[],char X[]) {
char Name[30];
FILE *arc;
arc=fopen(path,"rb");
fseek(arc,sizeof(int),SEEK_SET);
while (fread(Name,sizeof(char[30]),1,arc)) {
/*Here is when the errors happen..
The next sentence tell me that A.name don't have
the name from the second time*/
printf("%s and %s.",X,Name);
if (strcmp(Name,X)==0) return 1;
fseek(arc,2*sizeof(int),SEEK_CUR);
}
fclose(arc);
return 0
}
int main(int argc, char **argv)
{
char path[]="file.bin";
printf("\n%d",FSearch(path,"pedro"));
return 0;
}
The output is the following:
pedro and juan.pedro and .pedro and .
0
That means that is found the first name ('juan') but the second and third isn't (pedro and leo).
What is wrong?
Here's how it was:
fseek(arc,sizeof(int),SEEK_SET);
while (fread(Name,sizeof(char[30]),1,arc)) {
if (strcmp(A.name,X)==0) return 1;
fseek(arc,2*sizeof(int),SEEK_CUR); //--> ERROR
}
Here's how it should be:
fseek(arc,sizeof(int),SEEK_SET);
while (fread(Name,sizeof(char[30]),1,arc)) {
if (strcmp(A.name,X)==0) return 1;
fseek(arc,2*sizeof(int)+sizeof(char[2]),SEEK_CUR); //--> SOLVED
}
The problem was the 2nd argument, the Number of bytes to offset from origin, passed to fseek() call, within the while loop. It was counting two INTs but not the two CHARs (before reaching to the second string). You can see the sizeof(char[30]) after the fread() call, it shows 32 bytes, but 30 bytes are allocated to the string.
Why have to move two more bytes? Because any string have in its end, reserved bytes (for indicating the beginning and end of the string). e.g.:
char a[10]="Example";
If you save this into a binary file, this file will have a size of 12 bytes.
I would print the result of the fread call each time through the loop. I bet after the first object you're hitting EOF on the file. My prediction is that the first fread call returns 1, and the others return 0.
I don't know your binary file format.
Your code tell the binary file have names only with 30 characters.
struct alu{
int cod;
char name[30]; //juan - pedro - leo
int sex;
};
This structure size is not 38 bytes.
Check structure size.
printf("%d", sizeof(struct alu));
structure size depend on your compiler option...
If your binary format has bellow format.
{ // 1st record
cod = 10
names[30] = "juan"
sex = 1
}
{ // 2nd record
cod = 20
names[30] = "pedro"
sex = 1
}
{ // 3rd record
cod = 12
names[30] = "leo"
sex = 2
}
See your code.
#include <stdio.h>
#pragma pack(push, 1) or 4 or 8 depend on your binary format.
struct alu{
int cod;
char name[30]; //juan - pedro - leo
int sex;
};
#pragma pack(pop)
int FSearch(char path[],char X[]) {
char Name[30];
struct alu A;
FILE *arc;
arc=fopen(path,"rb");
//fseek(arc,sizeof(char[30]),SEEK_SET);
fseek(arc,0,SEEK_SET); // first record.
//while (fread(Name,sizeof(char[30]),1,arc)) {
while (fread(A,sizeof(A),1,arc)) {
/*Here is when the errors happen..
The next sentence tell me that A.name don't have
the name from the second time*/
printf("%s and %s.",X,A.name);
if (strcmp(A.name,X)==0) {
printf("Information of %s:\n",X);
//fshow_str(A);
fclose(arc);
return 1; // found
}
}
fclose(arc);
return 0; // not found
}
int main(int argc, char **argv)
{
char path[]="file.bin";
printf("\n%d",FSearch(path,"pedro"));
return 0;
}
cod size depend on compiler OPTION!!!
int FSearch(char path[],char X[]) {
char Name[30];
struct alu A;
FILE *arc;
arc=fopen(path,"rb");
fseek(arc,0,SEEK_SET); // first record.
//while (fread(Name,sizeof(char[30]),1,arc)) {
while (1) {
//if ( -1 == fseek(arc,4,SEEK_CUR)) // Important!!! case structure pack(4) for skip cod or
// break;
if ( -1 == fseek(arc,8,SEEK_CUR)) // Important!!! case structure pack(8) for skip cod
break;
if (!fread(Name,sizeof(Name),1,arc))
break;
A.name = Name;
/*Here is when the errors happen..
The next sentence tell me that A.name don't have
the name from the second time*/
printf("%s and %s.",X,A.name);
if (strcmp(A.name,X)==0) {
printf("Information of %s:\n",X);
//fshow_str(A);
fclose(arc);
return 1; // found
}
}
//if ( -1 == fseek(arc,4,SEEK_CUR)) // Important!!! case structure pack(4) for skip sex or
// break;
if ( -1 == fseek(arc,8,SEEK_CUR)) // Important!!! case structure pack(8) for skip sex
break;
fclose(arc);
return 0; // not found
}
Binary file and structure are alined with 4 bytes.
// Attention! pragma pack(push, 4) needs!!!
// Your now running machine is 32 bits system.
// This source code will invoke addressing fault 64 bits NON Intel processor.
#pragma pack(push, 4) // align 4 bytes.
struct alu{
int cod; // Integer type. 4 bytes on 32bits system. but 8 bytes on 64 bits system.
// I recommend using "long" type. "long" type is 4 bytes on any system.
char name[30]; //juan - pedro - leo
int sex; // also, Integer type.
};
#pragma pack(pop)
int FSearch(char path[],char X[]) {
char Name[30];
struct alu A;
FILE *arc;
arc=fopen(path,"rb");
fseek(arc,0,SEEK_SET); // first record.
//while (fread(Name,sizeof(char[30]),1,arc)) {
while (1) {
if ( -1 == fseek(arc,4,SEEK_CUR)) // Skip "cod" 4 bytes.
break;
if (!fread(Name,sizeof(Name),1,arc)) // Read "name" 30 bytes.
break;
if ( -1 == fseek(arc,2,SEEK_CUR)) // Skip "name"'s aligned 2 bytes.
break;
A.name = Name;
/*Here is when the errors happen..
The next sentence tell me that A.name don't have
the name from the second time*/
printf("%s and %s.",X,A.name);
if (strcmp(A.name,X)==0) {
printf("Information of %s:\n",X);
//fshow_str(A);
fclose(arc);
return 1; // found
}
}
if ( -1 == fseek(arc,4,SEEK_CUR)) // Skip "sex" 4 bytes.
break;
fclose(arc);
return 0; // not found
}
printf in main() printed the return value of FSearch(), if you want to see if the result is found, should at least return a bool value in FSearch()

Resources