Changing char* string in a C loop - c

I am trying to change a string within a loop to be able to save my images with a changing variable. Code snippet is as follows:
for (frames=1; frames<=10; frames++)
{
char* Filename = "NEWIMAGE";
int Save_Img = is_SaveImageMemEx (hCam, Filename, pMem, memID,
IS_IMG_PNG, 100);
printf("Status Save %d\n",Save_Img);
}
What I want to do is put a variable that changes with the loop counter inside Filename so my saved file changes name with every iteration.
Any help would be great.

Create a file name string with sprintf and use the %d format conversion specifier for an int:
char filename[32];
sprintf(filename, "NEWIMAGE-%d", frames);
sprintf works just like printf, but "prints" to a string instead of stdout.
If you declared frames as an unsigned int, use %u. If it is a size_t use %zu. For details see your friendly printf manual page, which will tell you how you can for example zero pad the number.
Be sure that the character array you write to is large enough to hold the longest output plus an extra '\0' character. In your particular case NEWIMAGE-10 + 1 means 11 + 1 = 12 characters is enough, but 32 is future-proof for some time.
If you want to program like a pro, look at the snprintf and asnprintf functions, which can limit or allocate the memory written to, respectively.

You can use sprintf to create a formatting string:
char Filename[50];
sprintf(Filename, "NEWIMAGE%d", frames);

Related

How to read and print hexadecimal numbers from a file in C

I'm trying to read 14 digit long hexadecimal numbers from a file and then print them. My idea is to use a long long int and read the lines from the files with fscanf as if they were strings and then turn the string into a hex number using atoll. The problem is I am getting a seg value on my fscanf line according to valgrind and I have absolutely no idea why. Here is the code:
#include<stdio.h>
int main(int argc, char **argv){
if(argc != 2){
printf("error argc!= 2\n");
return 0;
}
char *fileName = argv[1];
FILE *fp = fopen( fileName, "r");
if(fp == NULL){
return 0;
}
long long int num;
char *line;
while( fscanf(fp, "%s", line) == 1 ){
num = atoll(line);
printf("%x\n", num);
}
return 0;
}
Are you sure you want to read your numbers as character strings? Why not allow the scanf do the work for you?
long long int num;
while( fscanf(fp, "%llx", &num) == 1 ){ // read a long long int in hex
printf("%llx\n", num); // print a long long int in hex
}
BTW, note the ll size specifier to %x conversion in printf - it defines the integer value will be of long long type.
Edit
Here is a simple example of two loops reading a 3-line input (with two, no and three numbers in consecutive lines) with a 'hex int' format and with a 'string' format:
http://ideone.com/ntzKEi
A call to rewind allows the second loop read the same input data.
That line variable is not initialized, so when fscanf() dereferences it you get undefined behavior.
You should use:
char line[1024];
while(fgets(line, sizeof line, fp) != NULL)
To do the loading.
If you're on C99, you might want to use uint64_t to hold the number, since that makes it clear that 14-digit hexadecimal numbers (4 * 14 = 56) will fit.
The other answers are good, but I want to clarify the actual reason for the crash you are seeing. The problem is that:
fscanf(fp, "%s", line)
... essentially means "read a string from a file, and store it in the buffer pointed at by line". In this case, your line variable hasn't been initialised, so it doesn't point anywhere. Technically, this is undefined behavior; in practice, the result will often be that you write over some arbitrary location in your process's address space; furthermore, since it will often point at an illegal address, the operating system can detect and report it as a segment violation or similar, as you are indeed seeing.
Note that fscanf with a %s conversion will not necessarily read a whole line - it reads a string delimited by whitespace. It might skip lines if they are empty and it might read multiple strings from a single line. This might not matter if you know the precise format of the input file (and it always has one value per line, for instance).
Although it appears in that case that you can probably just use an appropriate modifier to read a hexadecimal number (fscanf(fp, "%llx", &num)), rather than read a string and try to do a conversion, there are various situations where you do need to read strings and especially whole lines. There are various solutions to that problem, depending on what platform you are on. If it's a GNU system (generally including Linux) and you don't care about portability, you could use the m modifier, and change line to &line:
fscanf(fp, "%ms", &line);
This passes a pointer to line to fscanf, rather than its value (which is uninitialised), and the m causes fscanf to allocate a buffer and store its address in line. You then should free the buffer when you are done with it. Check the Glibc manual for details. The nice thing about this approach is that you do not need to know the line length beforehand.
If you are not using a GNU system or you do care about portability, use fgets instead of fscanf - this is more direct and allows you to limit the length of the line read, meaning that you won't overflow a fixed buffer - just be aware that it will read a whole line at a time, unlike fscanf, as discussed above. You should declare line as a char-array rather than a char * and choose a suitable size for it. (Note that you can also specify a "maximum field width" for fscanf, eg fscanf(fp, "%1000s", line), but you really might as well use fgets).

How to store CHAR array to string MAC ADDRESS

I have a function that returns a unsigned char chMAC[6]; which is the mac address and i print it out as
printf("Mac: %x",chMAC[0]);
printf("%x",chMAC[1]);
printf("%x",chMAC[2]);
printf("%x",chMAC[3]);
printf("%x",chMAC[4]);
printf("%x\n",chMAC[5]);
And i get an output as Mac: B827E82D398E which is the actual mac address, but now i need to get that value as a string to pass to a sql parameter and i don't know how, since i need to add : in between. such as Mac: B8:27:E8:2D:39:8E
i bet this is easy, but i am still learning C.
You probably want all the bytes to be displayed as two characters:
%2x
but with a leading 0 instead of space:
%02x
You can string this all together in one printf call
printf("Mac: %02X:%02X:%02X:%02X:%02X:%02X\n"
, chMAC[0], chMAC[1], chMAC[2], chMAC[3], chMAC[4], chMAC[5]);
If you want the text to go to a sting buffer instead of stdout do this:
char buffer[32];
snprintf(buffer, sizeof(buffer)
, "Mac: %02X:%02X:%02X:%02X:%02X:%02X\n"
, chMAC[0], chMAC[1], chMAC[2], chMAC[3], chMAC[4], chMAC[5]);
You have all the pieces there, you just need to string them into the right order. Instead of using 6 separate printf() statements, pull it into one statement with all the formatting:
printf("Mac: %02X:%02X:%02X:%02X:%02X:%02X\n",
chMAC[0], chMAC[1], chMAC[2], chMAC[3], chMAC[4], chMAC[5]);
The "02" in the "%02X" formatting statements will put a leading zero if the value is <15; the capital X will make the alphabetic Hex digits into capitals (which is the usual convention when passing MAC addresses).
To send the resulting string to a buffer instead of to stdout, call sprintf (or even better, snprintf) with the same formatting string.
char mac_str[24];
snprintf(mac_str, sizeof(mac_str), "Mac: %02X:%02X:%02X:%02X:%02X:%02X\n",
chMAC[0], chMAC[1], chMAC[2], chMAC[3], chMAC[4], chMAC[5]);
why all the separate calls?
newlength = sprintf(mac, '%x:%x:%x:%x:%x:%x\n', chMAC[1], etc....)
You can have multiple %whatever format characters in a single printf/sprintf call...

Printf Variable String Length Specifier

I have a struct that contains a string and a length:
typedef struct string {
char* data;
size_t len;
} string_t;
Which is all fine and dandy. But, I want to be able to output the contents of this struct using a printf-like function. data may not have a nul terminator (or have it in the wrong place), so I can't just use %s. But the %.*s specifier requires an int, while I have a size_t.
So the question now is, how can I output the string using printf?
Assuming that your string doesn't have any embedded NUL characters in it, you can use the %.*s specifier after casting the size_t to an int:
string_t *s = ...;
printf("The string is: %.*s\n", (int)s->len, s->data);
That's also assuming that your string length is less than INT_MAX. If you have a string longer than INT_MAX, then you have other problems (it will take quite a while to print out 2 billion characters, for one thing).
A simple solution would just be to use unformatted output:
fwrite(x.data, 1, x.len, stdout);
This is actually bad form, since `fwrite` may not write everything, so it should be used in a loop;
for (size_t i, remaining = x.len;
remaining > 0 && (i = fwrite(x.data, 1, remaining, stdout)) > 0;
remaining -= i) {
}
(Edit: fwrite does indeed write the entire requested range on success; looping is not needed.)
Be sure that x.len is no larger than SIZE_T_MAX.
how can I output the string using printf?
In a single call? You can't in any meaningful way, since you say you might have null terminators in strange places. In general, if your buffer might contain unprintable characters, you'll need to figure out how you want to print (or not) those characters when outputting your string. Write a loop, test each character, and print it (or not) as your logic dictates.

Best way for BYTE array to HEX string conversion? (to avoid funny characters)

I have an application that needs to take the MsgId from a Websphere MQ message and write that as a file name on the file system....but have the HEX value string....
Note that a MsgId on Websphere MQ is actually a byte array of 24 long, and this is where I think my problem is coming in.
So here are some snippets of the code:
#define MSGID_LEN 24
#define MSGID_HEX_LEN 48
...
...
char *uuid = NULL;
char *buffer = NULL;
char msgid_hex[MSGID_HEX_LEN];
char *pmsgid_hex = msgid_hex;
char msgid[MSGID_LEN];
memcpy(msgid, md.MsgId, MSGID_LEN);
convertMsgIdToHex(pmsgid_hex, msgid);
uuid = malloc(MSGID_HEX_LEN * sizeof(char));
memcpy(uuid, pmsgid_hex, MSGID_HEX_LEN);
..
..
int convertMsgIdToHex(char *msgid_hex, char msgid[MSGID_LEN]){
int len = strlen(msgid);
int i;
for(i=0; i<len;i++){
sprintf(msgid_hex, "%02X", (unsigned char)msgid[i]);
msgid_hex +=2;
};
}
The problem is that their are sometime funny characters in the MSGID on Wensphere MQ and it seems I do not know how to convert these into there HEX equivalent.
For example, if I debug the application the MsgId is:
"AMQ QM01 \327\354\254N\027\232\002 "
And the hex string I get after the function above is:
"414D5120514D30312020202020202020D7ECAC4E179A0220"
This is fine, but sometimes I get funny characters like little hearts and symbols and when I try write the HEX string as a file name it works but has "invalid encoding" in the string as well....
What is the correct way I should work here? Should I convert from BYTE array to HEX string? If so do someone have a snippet of code on how I could possible change my function above to work with bytes instead of chars?
Should I be declaring my "char" variables are unsigned chars?
Thanks for the help ;-)
Lynton
You shouldn't use strlen to determine the message length: strlen should be used only for null-terminated strings. Since the message here is in a binary encoding, it may include embedded zeroes (which will cause the message to be truncated) or it may contain no zeroes - which will cause a buffer overflow since you will read past the end of the message.
Since apparently the message length is MSGID_LEN here, you should use that for the length.
Additionally, you need to make sure you output buffer is large enough. Its size should be at least 2*MSGID_LEN + 1: 2 characters for each input byte, plus one for the null terminator.

String format works in fprintf but doesn't work in sprintf, gives segmentation fault

fprintf(fp,"IP: %d: %.*s\n",
ip,
strstr(strstr(p->data, "User-Agent:"),"\n") - strstr(p->data, "User-Agent:"),
strstr(p->data, "User-Agent: ") );
fclose(fp);
Hi All, as you can see, in the above statement, I am trying to write off just the User Agent header from a char pointer which contains the entire http packet data. The thing is, After fiddling with the string format, I came up with this %.*s format which lets me, dynamically select the number of characters to be printed to the file, and then prints them. What the code is basically doing is, first, it's printing an int, then the number of chars from the occurrence of "User-Agent:" to the very next occurrence new line character is passed, and that amount of chars are then passes starting at where the "User-Agent:" starts, from the entire packet data string. I know it's all pretty messy, but it's working fine. Except that it's not working in sprintf.
Please save all my hard word! Any help is appreciated!
char *stat;
sprintf(stat,"%.*s\0",
strstr(strstr(p->data, "User-Agent:"),"\n") - strstr(p->data, "User-Agent:"),
strstr(p->data, "User-Agent: ")) ;
You are not allocating memory for stat. Try
char *stat = malloc(MAXLEN);
snprintf(stat, MAXLEN, ...);
^ ^
When you use sprintf, you need an array of characters to write into. You're writing to an uninitialized pointer.
Try this instead:
char stat[200];
sprintf(stat, etc...
Well, you are trying to write the data into uninitialized unallocated random memory location. Now that can't possibly work.
Either do:
char stat[SUFFICIENTLY_LARGE_NUMBER];
snprintf(stat, SUFFICIENTLY_LARGE_NUMBER, ...);
or:
char *stat = malloc(SUFFICIENTLY_LARGE_NUMBER);
snprintf(stat, SUFFICIENTLY_LARGE_NUMBER, ...);
and make sure "SUFFICIENTLY_LARGE_NUMBER" is enough bytes that the string fits in and not unnecessarily huge.
PS: snprintf, because your format does not include length limits. If it does, sprintf is OK, but never ever use sprintf with unlimited %s. Your %.*s, while formally limited, is not enough, because the expression will happily return more than the size of the allocated buffer, so you need another check to avoid overruning it.

Resources