Adding leading 'zeros' to a number without library in C - c

I wanted to store 'two zeros' in a value e.g. answer(which is a BYTE) and send it over to RS-485. How can I do that without any library?
Secondly, I tried by adding char '0' to zero(0) but instead it converted it to equivalent of zero which is '48' and send it over RS-485.
enter image description here
Thanks,

sprintf(buffer, sizeof buffer, "%03d", the_byte_number);
will do what you want, you can then send the buffer contents over the RS-485 using something like:
write(rs_485_file_descriptor, buffer, strlen(buffer);
if you refuse to use even the C standard library, you'll have to do the conversion yourself:
char *zero_pad(uint8_t numb, char *buffer)
{
static char tab[] = "01234567898";
/* you need to have at least three characters for the three digits in
* buffer, no check is made here for efficiency reasons.
* we advance the buffer 3 positions first, and then go backwards,
* filling with characters, from the least significant digit to the most.
* in case you want the string to be null terminated, you must start
* with the '\0' char.
*/
#if YOU_WANT_IT_NULL_TERMINATED
buffer += 4;
*--buffer = '\0';
#else
buffer += 3;
#endif
for (int i = 0; i < 3; i++) {
int dig = numb % 10;
*--buffer = tab[dig];
number /= 10;
}
return buffer;
} /* zero_pad */

What you describe as 'two zeros' are two nibbles in the hexadecimal representation of the BYTE 0. Of course if you add the ASCII character '0' to zero, you get 4810. If you just want to send the BYTE answer, no conversion is needed.
wr = write(fd, &answer, sizeof answer);

Related

Why number x is added only to the first number of a double digit unsigned?

I'm working on a TCP server using an ARM and i want to open the payload and add a number. My code for doing that is seen below:
unsigned rcv_buff;
unsigned *ptr = malloc(sizeof(*ptr));
unsigned *out_ptr;
out_ptr = &rcv_buff;
memcpy(ptr, p->payload, p->len);
rcv_buff = *ptr + 1;
/* in this case, we assume that the payload is < TCP_SND_BUF */
if (tcp_sndbuf(tpcb) > p->len) {
err = tcp_write(tpcb, out_ptr, p->len, 1);
free(ptr);
} else
xil_printf("no space in tcp_sndbuf\n\r");`
For 1 to 9 it works fine, but when i send 10 it send back ":". For double digit number, the 1 is added only to the first number. For example, when i send 23 it sends back 33.
Why number x is added only to the first number of a double digit unsigned?
All the signs point to the payload being a text representation of a number, as #EugeneSh. diagnosed in comments. In that case, you probably want to convert that to an actual number before performing arithmetic on it. Since it seems that you want to reply with a text representation of the result, you will also need to convert back.
Because the usual conversion functions work on strings, but there is no evidence that the message body itself provides a string terminator after the last digit, you probably want to copy the payload into a long-enough character array in order to work with it. That will also be useful for the back-conversion of the result.
// large enough for a representation of any 32-bit unsigned number as a decimal string:
char text[11] = {0}; // the array is initially zero-filled
int digits = 0;
if (p->len <= 0 || p->len >= sizeof text) {
// handle invalid-length payload ...
} else if (!isdigit((unsigned char) *p->payload)) {
// handle invalid payload starting with a non-digit ...
} else {
// Copy the payload to a separate buffer so that we can ensure a string terminator
memcpy(text, p->payload, p->len);
// the needed terminator is already present from the initialization of 'text'
// Parse the payload as an unsigned integer
char *end;
unsigned num = strtoul(text, &end, 10); // possible overflow; ignored
if (*end != '\0') {
// handle payload containing non-digits ...
}
// Write a text representation of the number plus one; assumes that the
// 'text' array is long enough to accommodate all possible `unsigned` values.
digits = snprintf(text, sizeof text, "%u", num + 1);
assert(digits < sizeof text); // fails only if text wasn't long enough after all
assert(0 < digits); // fails on output error, which should not happen for snprintf
}
The updated result is left in text, and the number of decimal digits (== the number of characters written to text, exclusive of the null terminator) is left in digits. Note well that digits may exceed p->len, such as when the input was "9" or "99".
I leave it to you to prepare and send a response message containing the updated number.

How to read caret notations from a binary file in C?

I have a requirement to read the characters in a binary file one byte at a time and concatenate them when a certain condition is met. I'm running into problems while reading the null character i.e ^# as denoted in the caret notations. Neither snprintf nor strcpy is helping me concatenate this null character with other characters. It is strange because when I print this character using
printf("%c",char1);
it prints out the null character in the caret notation i.e ^#. So my understanding is that even snprintf should have succeeded in concatenation.
Could anybody please let me know how can I achieve such a concatenation?
Thanks
C strings are null-terminated. If your input data can contain null bytes, you cannot use the string functions safely. Instead, consider just allocating a large-enough buffer (or dynamically resizing it as needed) and write each incoming byte to the right place in that buffer.
Since you're not working with raw ANSI strings, you can't use functions meant to be used with raw ANSI strings, because the way the interpret strings.
In C (and C++) strings are usually null terminated, i.e. the last character is \0 (value 0x00). At least this is true for standard functions for string manipulation and input/ouput (like printf() or strcpy()).
For example, the line
const char *text = "Hello World";
behind the scenes becomes
const char *text = "Hello World\0";
So when you're reading \0 from a file and putting it into your string, you essentially end up with an essentially empty string.
To make the issue more clear, just a simple example:
// Let's just assume the sequence 0x00, 0x01 is some special encoding
const char *input = "Hello\0\1World!";
char output[256];
strcpy(output, input);
// strncpy() is for string manipulation, as such it will stop once it encounters a null terminator
printf("%s\n", output); // This will print 'Hello'
memcpy(output, input, 14); // 14 is the string length above plus null terminator
printf("%s\n", output); // This will again print 'Hello' (since it stops at the terminator)
printf("%s\n", output + 7); // This will print "World" (you're skipping the terminator using the offset)
The following is a quick example I put together. It doesn't necessarily show best practice and it's also likely that there are a few bugs in there, but it should show you some possible concepts how to work with raw byte data, avoiding standard string functions wherever possible.
#include <stdio.h>
#define WIDTH 16
int main (int argc, char **argv) {
int offset = 0;
FILE *fp;
int byte;
char buffer[WIDTH] = ""; // This buffer will store the data read, essentially concatenating it
if (argc < 2)
return 1;
if (fp = fopen(argv[1], "rb")) {
for(;;) {
byte = fgetc(fp); // get the next byte
if (byte == EOF) { // did we read over the end of the file?
if (offset % WIDTH)
printf("%*s %*.*s", 3 * (WIDTH - offset % WIDTH), "", offset % WIDTH, offset % WIDTH, buffer);
else
printf("\n");
return 0;
}
if (offset % WIDTH == 0) { // should we print the offset?
if (offset)
printf(" %*.*s", WIDTH, WIDTH, buffer); // print the char representation of the last line
printf("\n0x%08x", offset);
}
// print the hex representation of the current byte
printf(" %02x", byte);
// add printable characters to our buffer
if (byte >= ' ')
buffer[offset % WIDTH] = byte;
else
buffer[offset % WIDTH] = '.';
// move the offset
++offset;
}
fclose(fp);
}
return 0;
}
Once compiled, pass any file as the first parameter to view its contents (shouldn't be too big to not break formatting).

Convert array of bytes to hexadecimal string in plain old C

I am looking into a method to convert a byte array to a hexadecimal string here is what i coded :
unsigned char buffer[] = {0xAA,0xBB,0x01,0xAB,0x11,0x12,0x13,0x22,0x11,0x14};
int _tmain(int argc, _TCHAR* argv[])
{
char * asta = (char*)malloc(16);
memset(asta,0,16);
int k;
for (k = 0; k < 16 ; k++)
{
sprintf(&asta[k],"%X",buffer[4 + k]);
}
printf("%s",asta);
_getch();
}
Only the first byte is converted correctly the rest are not. How can i fix the code ?
You have 10 bytes in your array, so your buffer needs at least 21 bytes (2 hex digits are needed for each byte + 1 for the null terminator).
I don't understand what you are doing here:
sprintf(&asta[k],"%X",buffer[4 + k]);
Why are you starting with the fifth byte in the buffer? Also, each byte in your buffer takes two bytes in the string, so you need to print to asta[2 * k].
Putting it together you get something like:
char * asta = (char*)calloc(2 * sizeof buffer + 1, sizeof(char)); // calloc automatically zeros asta
int k;
for (k = 0; k < sizeof buffer ; k++)
{
sprintf(&asta[2 * k],"%02X", (unsigned int)buffer[k]); // Not sure if the cast is needed
}
printf("%s",asta);
You have to remember that two-digit hexadecimal numbers will still be two digits when you print it as a string, i.e. it will take up two characters.
In the loop, the second iteration will overwrite the second character of the string, the third iteration will overwrite the third characters, etc.
Also, since each two-digit number will use two characters, you must allocate memory for 32 characters, plus one for the string terminating '\0' character.
And as noted in the comments, you are accessing data outside of your array.

sscanf doesn't move, scanning same integer everytime

I have a string that has ints and I'm trying to get all the ints into another array. When sscanf fails to find an int I want the loop to stop. So, I did the following:
int i;
int getout = 0;
for (i = 0; i < bsize && !getout; i++) {
if (!sscanf(startbuffer, "%d", &startarray[i])) {
getout = 1;
}
}
//startbuffer is a string, startarray is an int array.
This results in having all the elements of startarray to be the first char in startbuffer.
sscanf works fine but it doesn't move onto the next int it just stays at the first position.
Any idea what's wrong? Thanks.
The same string pointer is passed each time you call sscanf. If it were to "move" the input, it would have to move all the bytes of the string each time which would be slow for long strings. Furthermore, it would be moving the bytes that weren't scanned.
Instead, you need to implement this yourself by querying it for the number of bytes consumed and the number of values read. Use that information to adjust the pointers yourself.
int nums_now, bytes_now;
int bytes_consumed = 0, nums_read = 0;
while ( ( nums_now =
sscanf( string + bytes_consumed, "%d%n", arr + nums_read, & bytes_now )
) > 0 ) {
bytes_consumed += bytes_now;
nums_read += nums_now;
}
Convert the string to a stream, then you can use fscanf to get the integers.
Try this.
http://www.gnu.org/software/libc/manual/html_node/String-Streams.html
You are correct: sscanf indeed does not "move", because there is nothing to move. If you need to scan a bunch of ints, you can use strtol - it tells you how much it read, so you can feed the next pointer back to the function on the next iteration.
char str[] = "10 21 32 43 54";
char *p = str;
int i;
for (i = 0 ; i != 5 ; i++) {
int n = strtol(p, &p, 10);
printf("%d\n", n);
}
This is the correct behavior of sscanf. sscanf operates on a const char*, not an input stream from a file, so it will not store any information about what it has consumed.
As for the solution, you can use %n in the format string to obtain the number of characters that it has consumed so far (this is defined in C89 standard).
e.g. sscanf("This is a string", "%10s%10s%n", tok1, tok2, &numChar); numChar will contain the number of characters consumed so far. You can use this as an offset to continue scanning the string.
If the string only contains integers that doesn't exceed the maximum value of long type (or long long type), use strtol or strtoll. Beware that long type can be 32-bit or 64-bit, depending on the system.

Inserting leading zeros into an integer

I have a function in C which generates a number of hours from a rtc peripheral, which I then want to fill an array within a struct object. The array is set up to take 5 digits, but I need to prepend leading zeros to the number when it is less than 5 digits.
Could anyone advise on an easy way of achieving this?
char array[5];
snprintf(array, 5, "%05d", number)
A couple little routines that'll do what you want without having a printf() library hanging around. Note that there's not a way for the routines to tell you that the int you've passed in is too big for the buffer size passed in - I'll leave adding that as an exercise for the reader. But these are safe against buffer overflow (unless I've left a bug in there).
void uint_to_str_leading( char* dst, unsigned int i, size_t size )
{
char* pCurChar;
if (size == 0) return;
pCurChar = dst + size; // we'll be working the buffer backwards
*--pCurChar = '\0'; // take this out if you don't want an ASCIIZ output
// but think hard before doing that...
while (pCurChar != dst) {
int digit = i % 10;
i = i /10;
*--pCurChar = '0' + digit;
}
return;
}
void int_to_str_leading( char* dst, int i, size_t size )
{
if (size && (i < 0)) {
*dst++ = '-';
size -= 1;
i *= -1;
}
uint_to_str_leading( dst, i, size);
return;
}
Note that these routines pass in the buffer size and terminate with a '\0', so your resulting strings will have one less character than the size you've passed in (so don't just pass in the field size you're looking for).
If you don't want the terminating '\0' character because you're dealing with a fixed char[] array that's not terminated, it's easy enough to take out that one line of code that does the termination (but please consider terminating the char[] array - if you don't, I'll bet you'll see at least one bug related to that sometime over the next 6 months).
Edit to answer some questions:
dst is a pointer to a destination buffer. The caller is responsible to have a place to put the string that's produced by the function, much like the standard library function strcpy().
The pointer pCurChar is a pointer to the location that the next digit character that's produced will go. It's used a little differently than most character pointers because the algorithm starts at the end of the buffer and moves toward the start (that's because we produce the digits from the 'end' of the integer). Actually, pCurChar points just past the place in the buffer where it's going to put the next digit. When the algorithm goes to add a digit to the buffer, it decrements the pointer before dereferencing it. The expression:
*--pCurChar = digit;
Is equivalent to:
pCurChar = pCurChar-1; /* move to previous character in buffer */
*pCurChar = digit;
It does this because the test for when we're done is:
while (pCurChar == dst) { /* when we get to the start of the buffer we're done */
The second function is just a simple routine that handles signed ints by turning negative numbers into positive ones and letting the 1st function do all the real work, like so:
putting a '-' character at the start of the buffer,
adjusting the buffer pointer and size, and
negating the number to make it positive
passing that onto the function that converts an unsigned int to do the real work
An example of using these functions:
char buffer[80];
uint_to_str_leading( buffer, 0, 5);
printf( "%s\n", buffer);
uint_to_str_leading( buffer, 123, 6);
printf( "%s\n", buffer);
uint_to_str_leading( buffer, UINT_MAX, 14);
printf( "%s\n", buffer);
int_to_str_leading( buffer, INT_MAX, 14);
printf( "%s\n", buffer);
int_to_str_leading( buffer, INT_MIN, 14);
printf( "%s\n", buffer);
Which produces:
0000
00123
0004294967295
0002147483647
-002147483648
like #Aaron's solution, the only way to do it in C is to treat it like a character instead of a number. Leading zeros are ignored when they occur as a value and indicate an octal constant when appearing in code.
int a = 0000015; // translates to decimal 13.
Initialize every element in the array to 0 before inserting the digits into the array. That way you're guaranteed to always have 5 digits with leading zeroes.
If the type is int, then no. Set the type to string?
try this :
char source[5+1] = { '1','2', 0, 0, 0, 0 };
char dest[5+1];
int nd = strlen(source) ;
memset ( dest, '0', 5 - nd );
sprintf ( dest+nd+1, "%s", source );
Doesn't simple total bzero() or something like this and then filling with new value suit you? Could you please describe more details if not?
I'm not joking, I have seen several cases when total filling with 0 is faster then tricks to add 0s, especially if memory was cached and bzero() had some burst write support.
int newNumber [5] = 0;
for ( int i=0; givenNumber != 0 && i < 5 ; i++ ) {
newNumber[i] = givenNumber%10;
givenNumber = givenNumer/10;
}
apologies for the lack of detail. My code generates a 32-bit integer, which I am expecting to only get to 5 decimal digits in size. I then call the function:
numArray = numArrayFill(12345, buf, sizeof(buf));
(uint32_t number, char *buffer, int size)
{
char *curr = &buffer[size];
*--curr = 0;
do
{
*--curr = (number % 10) + '0';
number /= 10;
}
while (number != 0);
if (curr == buffer && number != 0)
return NULL;
return curr;
}
The problem comes when I put in a less than 5 digit number and I get random behaviour. What I need to do is to append zeros to the front so that it is always a 5 digit number.
Thanks
Dave

Resources