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()
Related
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.
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;
}
So I have a binary file that I want to read that is structured such that there are 256 segments of the following structure:
First Byte: integer representing the length of the bits of the field following it that you need to read. It doesn't necessarily end at a byte boundary
Variable number of bits: The field you want to read. It doesn't necessarily end at a byte boundary
The file ends with 0's padded out so that it ends at a byte boundary.
I'm struggling to figure out an ideal method that involves reading as few individual bits as possible. I'm thinking of maybe reading the length first, dividing this value by 8 and reading that number of bytes next, and then using remainder of the previous operation (if any) to read the rest of the field bit by bit. I'm not sure if this is an ideal method however. Any suggestions?
Edit: Attached is a link to the files. The readable file is the format I would like to print out the binary file as.
To take an example from the desired output:
length for 9c: 4
code for 9c: 1101
4 would be the first byte read from the binary file, and 1101 would be the variable number of bits
https://ln2.sync.com/dl/e85dc8b40/3f5wbhaq-kxz3ijv8-wuts3t32-442gbsh2
The naive method works excellently (for small files)
The input is actually completely unaligned, just a series of bits, without any padding.
[I'll delete this answer in 1 minute, because I dont want do do someone's homework]
#include <stdio.h>
#include <stdlib.h>
#define the_path "/home/Download/binary_file.dict"
struct bitfile {
FILE *fp;
unsigned char byte;
unsigned char left;
};
struct bitfile * bfopen(char *path)
{
struct bitfile *bp;
bp = malloc(sizeof *bp);
bp->fp = fopen(path, "rb" );
bp->byte = 0;
bp->left = 0;
return bp;
}
int bfclose(struct bitfile * bp)
{
int rc;
rc = fclose(bp->fp);
free(bp);
return rc;
}
int bfgetb(struct bitfile * bp)
{
int ch;
if (!bp->left) {
ch = fgetc(bp->fp);
if (ch < 0) return EOF;
bp->byte = ch;
bp->left = 8;
}
bp->left -= 1;
ch = bp->byte & (1u << bp->left) ? 1 : 0;
// bp->byte >>= 1;
return ch;
}
void bfflush(struct bitfile * bp)
{
bp->left =0;
}
unsigned bp_get_n( struct bitfile *bp, unsigned bitcount)
{
unsigned val=0;
while(bitcount--) {
int ch;
ch = bfgetb(bp);
if (ch < 0) return EOF;
val <<=1;
val |= ch;
}
return val;
}
int main(void)
{
struct bitfile *bp;
int ch;
unsigned iseg, ibit, nbit;
bp = bfopen( the_path);
for (iseg =0; iseg <16*16; iseg++) {
// bfflush(bp);
nbit = bp_get_n(bp, 8);
fprintf(stdout, "Seg%u: %u bits\n", iseg, nbit);
fprintf(stdout, "payload:");
for (ibit=0; ibit < nbit; ibit++) {
ch = bfgetb(bp);
if (ch < 0) break;
fputc( '0'+ ch, stdout);
}
fprintf(stdout, ".\n");
}
bfclose(bp);
return 0;
}
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.
i have built a small c program which i am trying to set a structure value
**static faut fautData**
typedef struct
{
char ds[25];
char ec[51];
char vc[51];
char rc[51];
char rb[2];
char eb[2];
char vb[2];
char es[10];
char dias[50];
char ss[10];
} faut;
i have a function name update to set values for the above specified structure
but when i try to set ** faut.es ** # the beginning of the update function the value does not get assigned(in my print call it does not get reflect.
when i set the same value # the end i i am able to print the output and see the value
why is that??
sample code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char ds[25];
char ec[51];
char vc[51];
char rc[51];
char rb[2];
char eb[2];
char vb[2];
char es[10];
char dias[50];
char ss[10];
} faut;
typedef struct
{
unsigned int d5;
unsigned int d10;
unsigned int d20;
unsigned int d50;
unsigned int d100;
unsigned int d500;
unsigned int d1000;
unsigned int an;
unsigned int rn;
unsigned int cn;
int alr;
}ncd;
static ncd chkncd;
int cdc;
void admin_init(void)
{
char Keys[17];
int i = 0;
int keysEnabled;
int shift = 0x01;
keysEnabled=0xFF;
strcpy(Keys,"0000000000000000");
//keysEnabled = getKeysToEnable();
for(i=0;i<8;i++)
{
switch((keysEnabled & shift))
{
case 0x10:
Keys[0]=0x34;
Keys[1]=0x36;
break;
case 0x20:
Keys[2]=0x34;
Keys[3]=0x37;
break;
case 0x40:
Keys[4]=0x34;
Keys[5]=0x38;
break;
case 0x80:
Keys[6]=0x34;
Keys[7]=0x39;
break;
case 0x08:
Keys[8]=0x34;
Keys[9]=0x34;
break;
case 0x04:
Keys[10]=0x34;
Keys[11]=0x33;
break;
case 0x02:
Keys[12]=0x34;
Keys[13]=0x32;
break;
case 0x01:
Keys[14]=0x34;
Keys[15]=0x31;
break;
default:
break;
}
shift = shift << 1;
}
printf("%s",Keys);
}
void update(void)
{
char temp[512];
int i = 0;
static faut fautData;
memset(&fautData, '\0', sizeof(fautData));
int cat =0;
if(cat) // Any failure
{
strncpy(fautData.ds, "3", 1);
strncpy(fautData.es, "4", 1);
memset(temp,'\0',sizeof(temp));
}
else
{
strncpy(fautData.es, "2",1);
strncpy(fautData.ds, "0",2);
}
strcpy(&fautData.ec[0],"00000000000000000000000000000000000000000000000000");//00000000000000000000000000000000000000000000000000
strcpy(&fautData.rc[0],"00000000000000000000000000000000000000000000000000");//00000000000000000000000000000000000000000000000000
strcpy(fautData.vc,"");
if(chkncd.d50 != 0){
memset(temp,'\0',sizeof(temp));
strcat(fautData.vc,"01");
sprintf(temp, "%03d", chkncd.d50);
strcat(fautData.vc,temp);
}
if(chkncd.d100 != 0){
memset(temp,'\0',sizeof(temp));
strcat(fautData.vc,"02");
sprintf(temp, "%03d", chkncd.d100);
strcat(fautData.vc,temp);
}
if(chkncd.d500 != 0){
memset(temp,'\0',sizeof(temp));
strcat(fautData.vc,"03");
sprintf(temp, "%03d", chkncd.d500);
strcat(fautData.vc,temp);
}
if(chkncd.d1000 != 0){
memset(temp,'\0',sizeof(temp));
strcat(fautData.vc,"04");
sprintf(temp, "%03d", chkncd.d1000);
strcat(fautData.vc,temp);
}
sprintf(fautData.vb, "%02d", chkncd.an);
fautData.rb[0] = 0x30;
fautData.rb[1] = 0x30;
fautData.eb[0] = 0x30;
fautData.eb[1] = 0x30;
strncpy(fautData.dias, "0", 1);
cdc = cdc - chkncd.an - chkncd.cn;
if ((chkncd.alr) || (cdc < 2450))
strncpy(fautData.ss, "4", 1);
else
strncpy(fautData.ss, "1", 1);
sprintf(temp,"keysEnabled:\nds : %s\nec : %s\n vc : %s\nrc : %s\n rb : %s\n eb : %s\n vb : %s\n es : %s\n ss : %s\n", fautData.ds, fautData.ec, fautData.vc, fautData.rc, fautData.rb, fautData.eb, fautData.vb, fautData.es, fautData.dias, fautData.ss);
printf("%s",temp);
}
int main(void) {
cdc=2300;
chkncd.d5=0;
chkncd.d10=0;
chkncd.d20=0;
chkncd.d50=0;
chkncd.d100=0;
chkncd.d500=1;
chkncd.d1000=0;
chkncd.alr=0;
chkncd.an=1;
chkncd.rn=0;
chkncd.cn=0;
update();
return EXIT_SUCCESS;
}
Your problem is here:
sprintf(fautData.vb, "%02d", chkncd.an);
fautData.vb is two bytes, but your sprintf call will write three bytes: the two-digit number followed by a null terminator, which overflows the vb array and overwrites fautData.es.
When you do
strncpy(fautData.es, "2",1);
you are copying "at most 1 character". This leaves you without the terminating null, and that can cause a problem. As the description says:
No null-character is implicitly appended at the end of destination if
source is longer than num. Thus, in this case, destination shall not
be considered a null terminated C string (reading it as such would
overflow).
You need to do
strncpy(fautData.es, "2",2);
to make sure you have a valid string.
Further, in your line
sprintf(fautData.vb, "%02d", chkncd.an);
You are putting a '\0' after .vb (so really you are writing three characters in total). But since vb only has space for two characters, the nul will be put as the first element of the next structure element - which happens to be .es. Thus, when you try to print .es, the first character is "end of string", and nothing gets printed.
If you change the struct to have three elements of space for vb:
char vb[3];
the problem goes away.
This is a tricky thing that happens all the time; you need one more space for each string than you have "characters". That '\0' takes space...
update as you said that you are constrained to have two bytes, you have to limit yourself to printing just two characters to the structure element during writing - and you have to limit yourself to printing only two characters during printing. Example:
void set_vb(int value) {
char temp[3];
sprintf(temp, "%02d", value);
memcpy(fautData.vb, temp, 2);
}
void print_vb(void {
printf("%.2s", fautData.vb);
}
Now you can forget "how to do it right", and just call these two functions when you need to set or print the value of vb. You could do the same for other elements where you run into this issue (given the tight size of your struct, that could apply to many of them...)