Huinia Huini Huinia Huini - 1 month ago 8
C++ Question

fgetc() reads 0c symbol and array elements are nullified? why is that?

I have noticed interesting thing but I am not sure if it is supposed to happen this way.

I got some code that uses fgetc(); to read symbols from file and store them into an int say l;

l=fgetc(file);


file is opened in read binary mode ("rb"); using

file=fopen("filename", "rb");


then using string stream each symbol is converted into hex format and sent into a string and then stored in a char array;

std::stringstream sl;


sl << std::hex << l; sl >> sll;

char as[i]=sll[i];


The problem is that when fgetc(); reads a symbol that in an ascii table is represented as OC in hex format or FF as char my final char array gets filled with 0's.

In short if char[] element contains 0c the rest of elements are 0's;

I have no idea why this happens. When I edited my file using hex editor and replaced 0c with something else. That file was read properly and all symbols got stored in an array as they were written in the file.

If you could tell how to circumvent such behaviors, I would appreciate that.

Ok. Full code:

#include <stdio.h>
#include<iostream>
#include <string.h>
#include "u.c"
#include <wchar.h>
#include <sstream>

int main() {
unsigned long F, K;
std::string k;
char hhh[300];
char hh1[300];
char kk[64];
int lk;

memset(kk, 0, 64);

FILE *diy;
FILE *ydi;

std::cin >> k;
std::cin >> hhh;
std::cin >> hh1;
lk = k.length();

for (int i = 0; i < lk; i++) {
kk[i] = k[i];
}

;
bof(kk, lk);
diy = fopen(hhh,"rb");
ydi = fopen(hh1,"wb");

int mm = 0;
int l;
int r;
char ll[9];
char rr[9];

memset(ll, 0, 9);
memset(rr, 0, 9);

std::string sll;
std::string slr;
char sL[3];
char sR[3];
int i = 0;

while (!feof(diy)) {
l = fgetc(diy);
r = fgetc(diy);

std::stringstream sl;
std::stringstream sr;

sl << std::hex << l;
sl >> sll;
sL[0] = sll[0];
sL[1] = sll[1];
sr << std::hex << r;
sr >> slr;
sR[0] = slr[0];
sR[1] = slr[1];

if (i == 0) {
ll[0] = sL[0];
ll[1] = sL[1];
ll[2] = sR[0];
ll[3] = sR[1];
sL[0] = '\0';
sR[0] = '\0';
sL[1] = '\0';
sL[1] = '\0';
}

;

if (i==1) {
ll[4] = sL[0];
ll[5] = sL[1];
ll[6] = sR[0];
ll[7] = sR[1];
sL[0] = '\0';
sR[0] = '\0';
sL[1] = '\0';
sL[1] = '\0';
}

;

if (i == 2) {
rr[0] = sL[0];
rr[1] = sL[1];
rr[2] = sR[0];
rr[3] = sR[1];
sL[0] = '\0';
sR[0] = '\0';
sL[1] = '\0';
sL[1] = '\0';
}

;

if(i==3){
rr[4] = sL[0];
rr[5] = sL[1];
rr[6] = sR[0];
rr[7] = sR[1];
sL[0] = '\0';
sR[0] = '\0';
sL[1] = '\0';
sL[1] = '\0';
}

;

sL[0] = '\0';
sR[0] = '\0';
sL[1] = '\0';
sL[1] = '\0';

if (i == 3) {
printf(" %s %s \n ", ll, rr); //indicated that my rr array had problems with that 0x0c;
sscanf(ll, "%08lX", &F);
sscanf(rr,"%08lX",&K);
printf(" before %08lx %08lx \n ", F, K);
omg( &F, &K);
printf(" after %20lx %20lx \n ", F, K);
memset(ll, 0, 9);
memset(rr, 0, 9);

char RR[9];

sprintf(RR, "%08lx", F);

char LL[9];

sprintf(LL, "%08lx", K);
printf(" %s %s ", LL, RR);

for (int j = 0; j < 4; j++) {
char ls[3];

ls[0] = LL[j*2];
ls[1] = LL[2*j+1];

int kj;

std::stringstream op;
op << ls;
op >> std::hex >> kj;
fputc(kj, ydi);
}

;

for(int j = 0; j < 4; j++) {
char lr[3];

lr[0] = RR[j*2];
lr[1] = RR[2*j+1];

int kjm;

std::stringstream ip;
ip << lr;
ip >> std::hex >> kjm;
fputc(kjm,ydi);
}

;

memset(LL, 0 ,9);
memset(RR, 0, 9);
}

;
i++;
std::cout << "\n";

if (i == 4) {
i = 0;
}

;
}

;

fclose(diy);
fclose(ydi);
}

;


Since you asked, now you have it.


  1. this code will not compile because you do not have necessary libraries.

  2. simplified code is at the beginning of this post.

  3. those libraries that you do not posses have nothing to do with this issue.


Answer

The core problem

You assume that

std::stringstream the_stream;
std::string the_string;

the_stream << std::hex << 0x0C;
the_stream >> the_string;

results in the_string containing "0c". However, it will contain "c".

This means that later on, you end up converting the input "\x0c\xfe" to 'c', '\0', 'f', 'e'. If you use this at any point in a C-style string, of course it ends the string after c.


It was quite hard to debug this program. In the future, please write readable and understandable code. What follows is a non-exhaustive list of the problems I found.

Design problems

  • while(!feof(file)) is always wrong.
  • Use variable scoping. If you pull the declaration of sL and sR into the loop, you don't have to reset them. Less code, less potential errors.
  • You're using a lot of code for something as simple as converting a presumably 8-bit char to its hexadecimal representation. In fact, the only reason you ever use std::stringstream in your code is to do exactly that. Why don't you isolate this functionality to a function?

Irrelevant problems

  • Because of the poor code formatting, you probably didn't notice the copy-paste errors in the use of sL and sR:

    sL[0] = '\0';
    sR[0] = '\0';
    sL[1] = '\0';
    sL[1] = '\0';
    

    Obviously, that last line should read sR[1] = '\0';

Style problems

There are many, many things wrong with your code, but one thing that easily stops people from helping is formatting. The space formatting in particular made your code very hard to read, so I took the liberty to edit the "full" code in your question to have (almost) consistent formatting. A few basic problems become evident:

  • Use meaningful names for variables and functions. I have no idea what you're trying to do here, which doesn't help in finding the real problem in the code.
  • Mixing <iostream> and <stdio.h> doesn't help the readability of your code. Choose one or the other. In fact, only ever use <iostream> in C++.
  • Besides that, use the appropriate header names for C++ (<cstring> and <cwchar> instead of <string.h> and <wchar.h>).
  • Don't write a semicolon after a compound statement. Instead of

    int main(void) {
        if (condition) {
            one_statement();
            another_statement();
        };
    };
    

    you should write

    int main(void) {
        if (condition) {
            one_statement();
            another_statement();
        }
    }
    

    The ; is part of a separate statement. It also prevents you from using else constructs.

  • Use initialisers where appropriate. So don't write

    char ll[9];
    char rr[9];
    
    memset(ll, 0, 9);
    memset(rr, 0, 9);
    

    while

    char ll[9] = { 0 };
    char rr[9] = { 0 };
    

    is more readable.