What format specifier should I use here? - c

Got this code right here to print out the name of an opened file (its a height map in case you were wondering) and every time I try to print out I get format warnings, which format specifier should I use for this?
unsigned char* data = stbi_load("textures/height.png", &width, &height, &nr_components, 0);
printf("Loaded file: %u\n", data);

If your goal is to print the address where the data was loaded, that would be %p:
printf("Loaded file: %p\n", (void*)data);
If you want to print the actual data, byte by byte, you should loop over the bytes and use %hhu (for decimal) or %hhx (for hexadecimal):
printf("Loaded file:\n");
for(int i = 0; i < width*height*nr_components; ++i)
printf("%hhx ", data[i]);
printf("\n");
data doesn't contain the name of the file though, so if you want to print just the name, then print that same string that you passed to stbi_load:
const char *filename = "textures/height.png";
unsigned char* data = stbi_load(filename, &width, &height, &nr_components, 0);
printf("Loaded file: %s\n", filename);

Related

function to read an input from a buffer that contains a file

I have this function that communicates with a tcp server
char write_buffer[128];
char read_buffer[128];
char hint_status[4];
char Fsize[10];
FILE *score;
char lnk[1024];
int Fsize_max = 1024*1024*1024;
int hint(){
if (connect(tcpfd, tcpres->ai_addr, tcpres->ai_addrlen) < 0) {
printf("\n Error : Connect Failed \n");
return 0;
}
sprintf(write_buffer,"GHL %s\n",PLID);
n=write(tcpfd, write_buffer,strlen(write_buffer));
n=read(tcpfd, read_buffer, 128);
sscanf(read_buffer, "%s %s %s %s %s\n", message_type, hint_status, Fname, Fsize, lnk);
if(strcmp(hint_status, "NOK") == 0){
return 0;
};
if (atoi(Fsize) > Fsize_max){
printf("size_overflow\n");
return 0;
}
score = fopen(Fname, "w+");
fwrite(lnk, 1, sizeof(lnk), score);
fclose(score);
return 0;
}
That sends information to the server and in return is supposed to receive "RHL status [Fname Fsize Fdata]" in what status is to check if the it return a file or not, and
the filename Fname (it comes in .PNG or .JPG)
the file size Fsize, in bytes;
the contents of the selected file (Fdata).
I am supposed to receive RHL OK something.PGN 99123(for example) data and I am receiving RHL OK 5 12 or some times segmentation fault.
I know I am doing something wrong but I am not surely what.
Does any body have a clue on what is wrong with it?
Does any body have a clue on what is wrong with it?
Yes
Missing null character
n=write(tcpfd, write_buffer,strlen(write_buffer)); does not write a string as no null character is sent.
Consider
n=write(tcpfd, write_buffer,strlen(write_buffer) + 1);
sscanf(read_buffer... expects a string, yet read_buffer[] is not certainly null character terminated.
Use return value n to examine read_buffer[] and determine and append a '\0' as needed.
Candidate problem: no width
Without widths, code risks buffer overflow and undefined behavior (UB).
char Fsize[10]; cannot save as text, Fsize_max, or "1073741824", which needs size 11.
Use widths to prevent buffer overflow.
Use better scan checking
// sscanf(read_buffer, "%s %s %s %s %s\n",
// message_type, hint_status, Fname, Fsize, lnk);
char message_type[10]; // True size is unknown as not posted by OP.
char Fname[100]; // True size is unknown as not posted by OP.
int n = 0;
sscanf(read_buffer, "%9s %3s %99s %9s %1023s %n",
message_type, hint_status, Fname, Fsize, lnk, &n);
if (n == 0 || read_buffer[n]) {
TBD_CODE_Handle_Error():
}
For error checking, do not assume text in int range.
// if (atoi(Fsize) > Fsize_max){
if (atoll(Fsize) > Fsize_max){

Write Hex into a file (not as ASCII) in C

I'm trying to write a file with hex values representation in C
something like this:
char Msg[4] = {0x3f, 0x2a, 0x01, 0x52};
the output that I'm looking for into the file is like this: "3f2a0152"
I was using fprintf to append some text before the hex representation, but I was not able to write it successfully
FILE *LOG_FILE= fopen("./Hex.log", "a");
fprinf(LOG_FILE, "%d OUT %x", Timestamp, Msg);
fclose(LOG_FILE);
Any advise?
The line:
fprintf(LOG_FILE, "%d OUT %x", Timestamp, Msg);
will decay Msg to a pointer (address of the 0x3f) and then print that out.
What you need to do is to output each element as a two-digit hex value, something like:
fprintf(LOG_FILE, "%d OUT %02x%02x%02x%02x\n", Timestamp, Msg[0], Msg[1], Msg[2], Msg[3]);
In addition, they should probably be specified as unsigned char so they don't sign-extend when passing to fprintf. Otherwise, you'd have to do something ugly like:
fprintf(LOG_FILE, "%d OUT %02x%02x%02x%02x\n", Timestamp, (unsigned)(Msg[0]),
(unsigned)(Msg[1]), (unsigned)(Msg[2]), (unsigned)(Msg[3]));
If you wanted a more general solution, you could put together a function to do it, something like:
void LogHex(FILE *fh, int tstamp, char *preamble, unsigned char *mem, size_t sz) {
fprintf(fh, "%d %s", tstamp, preamble);
for (size_t i = 0; i < sz; ++i) {
fprintf(fh, "%02x", mem[i]);
}
fprintf(fh, "\n");
}
:
LogHex(LOG_FILE, Timestamp, "OUT ", Msg, sizeof(Msg));

Reading a line from a file at a specific point

so Im writing a code to get scanf a text file and return a format text message log. I'm stuck wondering how to scan strings from file at a certain point and print every string beyond that point E.X When the file scans the line
"332982000 2055552002 2055551001 7 Mr Webb, can I ask you a question?" I scan the first 4 numbers as integers and scan the rest of the written text into an char array starting at "Mr. Webb".
I tried using a for loop with fscanf to scan into an array but it didnt work. I was also thinking I could use malloc just to save space but I dont know what to put in the sizeof argument. Any help would be GREATLY appreciated!
int posix;
int phone1;
int phone2;
int textsize;
int val, val2;
char line[256];
char text[3000];
int len=strlen(line);
int i=0;
printf("\n\nTime %s %s", argv[2], argv[3]);
printf("\n======================================================================================\n\n\n");
FILE* textfile= fopen(argv[1],"r");
fscanf(textfile, "%d %d %d %d %s", &posix, &phone1, &phone2, &textsize, text);
while( fgets(line, sizeof(line), textfile) ) {
val= atoi(argv[2]);
val2=atoi(argv[3]);
if ( (val==phone1) && (val2==phone2) ) {
printf(" %s ", text); //only prints Mr
text=(char*)malloc(sizeof())//tried malloc but not too sure how to use it correctly
for (i=0; i<len; i++) { //tried using for loop here didnt work.
fscanf("%s", text);
}
sortText(phone1, phone2, textsize, text);
//readableTime(posix);
}
else if ( (val2==phone1) && (val==phone2) ) {
printf(" %s ", text);
sortText(phone1, phone2, textsize, text);
//readableTime(posix);
}
fscanf(textfile, "%d %d %d %d %s", &posix, &phone1, &phone2, &textsize, text);
}
fclose(textfile);
return 0;
}
At first, read the entire file into a malloc'd char array. The fseek and ftell give you the file size:
// C99
FILE *fp = fopen("file", "r");
size_t filesize;
fseek(fp, 0, SEEK_END);
filesize = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *filetext = malloc(filesize + 1);
fread(filetext, 1, filesize, fp);
filetext[filesize] = 0;
Then use a buffer for a single line with the size of the entire file so you surely have enough size. sscanf() can be used to read stuff from a string.
int readbytes;
for(int i=0; i < filesize; i+=readbytes) {
char line[filesize];
int posix, phone1, phone2, textsize;
if(EOF == sscanf(
&filetext[i], "%d%d%d%d%[^\n]%n", &posix, &phone1,
&phone2, &textsize, line, &readbytes))
{
break;
}
printf("%d %d %d %d '%s' %d\n", posix, phone1, phone2, textsize, line, readbytes);
}
The format specifier '%[^\n]' means: every character until the next newline character. The format specifier '%n' gives you the number of bytes that have been read with this sscanf call so far, effectively your line size, that you can use to advance the iterator.

Converting text to a binary file

I need to convert a text file of the following format to binary:
The first line contains the number of products in the inventory, The following lines contains:
product name '\t' product price '\t' quantity '\n'
(there can be more than one \t between columns)
For every product the binary output file will contain an int representing the length of the product name, the chars that hold the product name, an int representing the price and an int representing the quantity.
Sample input file:
Asus Zenbook 1000 10
iPhone 5 750 22
Playstation 4 1000 0
I have wrote the following code, and I understood that I'm supposed to see the string in plain text while the integers will show up as gibberish (in binary):
int convertTextToBinary(char *fileName)
{
FILE *pText, *pBinary;
int size, i;
char *currProdName;
int currProdNameLen, currQuantity, currPrice;
if (checkFileExists(fileName) == FALSE)
{
printf("- Given file does not exists!\n");
return ERROR;
}
else
pText = fopen(fileName, "r");
// get the number of products in the inventory
fscanf(pText, "%d", &size);
#ifdef DBG
printf("##DBG Successfuly read &size = %d DBG##\n", size);
#endif
pBinary = fopen(strcat(fileName, ".bin"), "wb");
fwrite(&size, sizeof(int), 1, pBinary);
#ifdef DBG
printf("##DBG Successfuly wrote &size = %d DBG##\n", size);
#endif
for (i = 0; i < size; i++)
{
// get product name and name length
currProdNameLen = getProdName(pText, &currProdName);
#ifdef DBG
printf("##DBG %d Successfuly read &currProdName = %s DBG##\n", i+1, currProdName);
printf("##DBG %d Successfuly read &currProdNameLen = %d DBG##\n", i+1, currProdNameLen);
#endif
// get product price
fscanf(pText, "%d", &currPrice);
printf("##DBG %d Successfuly read &currPrice = %d DBG##\n", i+1, currPrice);
// get product quantity
fscanf(pText, "%d", &currQuantity);
printf("##DBG %d Successfuly read &currQuantity = %d DBG##\n", i+1, currQuantity);
// write data to binary file
fwrite(&currProdNameLen , sizeof(int), 1, pBinary);
fwrite(&currProdName, sizeof(char), currProdNameLen, pBinary);
fwrite(&currPrice, sizeof(int), 1, pBinary);
fwrite(&currQuantity, sizeof(int), 1, pBinary);
free(currProdName);
}
fclose(pText);
fclose(pBinary);
return 1;
}
/* This function checks if a file in a given path exists or not by using fopen with "read" argument */
BOOL checkFileExists(char *fileName)
{
FILE *fp;
fp = fopen(fileName, "r");
// file does not exists
if (fp == NULL)
return FALSE;
// file does exists
else
{
fclose(fp);
return TRUE;
}
}
int getProdName(FILE *fp, char **prodName)
{
int nameLen = 0, offset;
// count the length of the product name
while (fgetc(fp) != '\t')
nameLen++;
// allcoate memory for the product name
*prodName = (char*)malloc(sizeof(char)*nameLen);
//checkalloc(&prodName);
// get the cursor back to the original position
offset = -1 * nameLen;
fseek(fp, offset, SEEK_CUR);
// copy product name from text to string
fgets(*prodName, nameLen, fp);
return strlen(*prodName);
}
But the hell, my output file looks like this:
¨ ּּּּּט ¨ ּּּ¯ ¨ ּּּּּּּּ ּּּ«
¨
Which holds no plain text. I have tried changing the fopen argument from "wb" to "w" but I still get gibberish files. What am I doing wrong?
Here you write the pointer and additional garbage instead of the string it points to:
fwrite(&currProdName, sizeof(char), currProdNameLen, pBinary);
You should use:
fwrite(currProdName, sizeof(char), currProdNameLen, pBinary);
In your version you are passing the pointer to the pointer, but you want to pass the pointer itself.
BTW: In your function getProdName(), you should add an additional character, because you are allocating the exact string lenght, but no room for the 0 Byte at the end. This can also cause problems. Also fgets reads one char less. Check the man page for fgets. Instead of using fgets, you can also use fread because you know the length anyway. No additional parsing needed.
update
Change this:
fscanf(pText, "%d", &currQuantity);
to
fscanf(pText, "%d\n", &currQuantity);

Read a file line by line for integers

I just want to output 3 integers from the file. Why this doesn't work? I get -1079184140 and similar.
int main(int argc, char *argv[])
{
FILE* stream = fopen(argv[2], "r");
char line[80];
for (int i = 0; i < 3; i++)
{
fgets(line, 80, stream);
printf("%d \n", line);
}
fclose(streamForInput);
}
I would use sscanf.
int number;
sscanf (line, "%d", &number);
printf ("%d \n", number);
That will pull the first integer on a line. This is not the most secure or robust way, but that is out of scope.
PS:
fclose(streamForInput);
Should be:
fclose(stream);
Hmm. The first problem is:
printf("%d \n", line);
because line is a char[]. But you use a %d to output it, so you output line, which is an address. So printf prints the address of line... instead you coud use printf ("%d", atoi(line));
To print a string, which line is, use %s:
printf("%s \n", line);
Now, if it really were an integer, you could use %d:
int num = atoi(line);
printf("%d \n", num );
What you're seeing is the result of treating a pointer type (which is what a string in C basically is) as an integer type. Since pointers hold memory addresses, that -1079184140 is the actual address the pointer holds, represented as a 32 bit signed integer.
If you know exactly the content of the file (three numbers separated by white space), why not directly read it?
if (fscanf(stream, "%d%d%d", &foo, &bar, &baz) < 3)
// handle error
printf("%d\n%d\n%d\n", foo, bar, baz);
But if you want to read lines, there are already other good answers.
To read a file line by line for integers
void read_file(char *filename, int *readbuff, int size)
{
FILE *fp = fopen(filename,"r");
if(fp == NULL){
printf("Failed to open file %s \n", filename);
return;
}
/*the condition in for loop checks if the integer was read into
readbuff[i] and the readbuff is not overflown*/
for(int i = 0 ; fscanf(fp,"%d\n",&readbuff[i]) == 1 && i < size; ++i);
fclose(fp);
return;
}

Resources