Question :
I know I should be using a character array but character data are stored in as their corresponding numerical value; So we can say both int array and character array are same the only difference is; generally character uses 1 byte and int uses 4 bytes.
My Problem :
I have an int array; I am storing data into that array but when I tried to print that array using printf and %s its only printing first character from that array
When %s is used with printf it searches for null character i.e. \0, to know where to stop. In my code I am putting /0 explicitly to the end of string.
Code(Edited) :
/* Write a program to print all input lines that are longer than 80
characters. */
#include <stdio.h>
#define MAXCHAR 80
#define LINES 1000
int main() {
int i, c = 0;
int data[LINES];
while(c != EOF) {
for(i = 0; i < LINES - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
data[i] = c;
printf("Value of i after for = %d\n",i );
if(c == '\n') {
data[i] = c;
++i;
}
data[i] = '\0';
if(i >= MAXCHAR + 2)
printf("%s\n",data);
printf("Value of i = %d\n",i );
}
}
If you have a char array containing the string "Hello\0" it will look like this:
+---+---+---+---+---+---+
| H | e | l | l | o |\0 |
+---+---+---+---+---+---+
Or if we show the integer value of those characters it looks like this:
+-----+-----+-----+-----+-----+-----+
| 72 | 101 | 108 | 108 | 111 | 0 |
+-----+-----+-----+-----+-----+-----+
So if we have an array of int containing the same values it looks like this:
+-----------+-----------+-----------+-----------+-----------+-----------+
| 72 | 101 | 108 | 108 | 111 | 0 |
+-----------+-----------+-----------+-----------+-----------+-----------+
Or in hexadecimal, and assuming 16-bit ints, it looks like this:
+------+------+------+------+------+------+
| 0048 | 0065 | 006C | 006C | 006F | 0000 |
+------+------+------+------+------+------+
Or looking at the individual bytes, and assuming little-endian byte order, it looks like this:
+----+----+----+----+----+----+----+----+----+----+----+----+
| 48 | 00 | 65 | 00 | 6C | 00 | 6C | 00 | 6F | 00 | 00 | 00 |
+----+----+----+----+----+----+----+----+----+----+----+----+
So if we have an int array containing the integers corresponding to the characters in a string, and if (despite the gross type incompatibility) we try to print them using printf and %s, it will look at the first byte which is 48 which is an H, and print it, but then right after that it will see a 0 byte, which it will interpret as the end of the string, and stop.
Related
In C language, I want to fill two 8-bit variables "a" and "b" with bits coming from a 16-bit variable "c".
The bits in the 16 bits variable are shuffled without any logical order, which can be for example :
a.4 | b.2 | b.6 | b.0 | a.0 | a.7 | a.6 | b.1 | b.2 | b.7 | b.4 | a.5 | a.1 | a.2 | b.3 | b.5
Is there a way to do that?
The goal is to have a quite lisible look-up table.
This code randomizes and shuffles bits in c after copying initial, you stated it is intended to be used in a embedded system but you didn't provide any information about which embedded system it is, it could be an arduino, it could be a obscure system from 80s, it could be a diy pcb with a random stm32 attached to it, we can't know :)
// Code is under public domain, use it like what you want
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <time.h>
int main() {
srand(time(NULL));
uint16_t initial = 4040; /* 24 will be shuffled */
uint16_t c = 0;
/* shuffle bits */
for(unsigned i = 0; i < sizeof(uint16_t) * 8; ++i) {
c ^= initial & (1 << (rand() % 16));
}
uint8_t a = 0;
uint8_t b = 0;
a = ((unsigned char*)&c)[0];
b = ((unsigned char*)&c)[1];
for(unsigned char i = 0; i < sizeof(uint16_t) * 8; ++i) {
printf("%c.%d = %d | ", ('a' * ((i < 8))) + ('b' * ((i >= 8))), ((i + 1) * (i < 8)) + ((i + 1 - 8) * (i >= 8)), ((a >> i)) & 1);
}
return 0;
}
This code will print this (obviously yours going to be random):
a.1 = 1 | a.2 = 0 | a.3 = 1 | a.4 = 1 | a.5 = 0 | a.6 = 1 | a.7 = 1 | a.8 = 1 | b.1 = 0 | b.2 = 0 | b.3 = 0 | b.4 = 1 | b.5 = 0 | b.6 = 1 | b.7 = 0 | b.8 = 0 |
This question already has answers here:
Endianness -- why do chars put in an Int16 print backwards?
(4 answers)
Closed 3 years ago.
I have following code:
int main ( void ) {
unsigned int array [] = { 298 , 0 x1A2A3A4A };
unsigned char *p = ( unsigned char *) array ;
for (int i = 4; i < 8; i ++) {
printf ("% hhX ", p[i]) ;
}
printf ("\ nThe Answer is %d or %d!\n", p[0] , p [6]) ;
return EXIT_SUCCESS ;
}
I dont understand the output:
4A 3A 2A 1A
The Answer is 42 or 42
On a little endian system, the layout of the 8 byte array is
Position: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
Value (Hex): 2A | 01 | 00 | 00 | 4A | 3A | 2A | 1A
Your loop prints the last 4 bytes in the order they appear in the array. Your final printf prints the values at the 0 and 6 position, which are both 0x2A, or 42 in decimal.
I am using the following approach to print the binary of an ascii character:
unsigned char bitmask = 0b10000000;
char _my_char = 'a';
for (int i=0; i<8; i++) {
if (i==4) putchar(' '); // separate every four characters
printf("%d", (_my_char & bitmask) != 0);
bitmask = bitmask >> 1;
}
putchar('\n');
return 0;
How could I generalize this so that, for example, I could print the binary of any data type/structure? One byte per row?
There are numerous ways to do this. The following outputs a nice chart of printable characters giving the value for each character in ASCII, decimal, hex and binary, e.g.
#include <stdio.h>
#include <limits.h>
/* CHAR_BIT */
#ifndef CHAR_BIT
#define CHAR_BIT 8
#endif
int main (void) {
char c = 0; /* character */
int i = 0; /* int loop counter */
printf ("\nchar | int | hex | binary\n");
printf ("-----+-------+--------+---------\n");
for (c = 32; c <= 126; c++) { /* for each char in printable range */
/* output the character, decimal, hex and binary */
printf (" %c | %3d | 0x%02x | ", c, c, c);
for (i = sizeof (c) * CHAR_BIT - 1; i >= 0; i--) /* for each bit */
printf ("%d", ((c >> i) & 0x1) ? 1 : 0); /* output 0/1 */
putchar ('\n'); /* output \n */
}
putchar ('\n');
}
Example Use/Output
$ ./bin/bin_ascii
char | int | hex | binary
-----+-------+--------+---------
| 32 | 0x20 | 00100000
! | 33 | 0x21 | 00100001
" | 34 | 0x22 | 00100010
# | 35 | 0x23 | 00100011
$ | 36 | 0x24 | 00100100
% | 37 | 0x25 | 00100101
& | 38 | 0x26 | 00100110
' | 39 | 0x27 | 00100111
( | 40 | 0x28 | 00101000
) | 41 | 0x29 | 00101001
* | 42 | 0x2a | 00101010
+ | 43 | 0x2b | 00101011
, | 44 | 0x2c | 00101100
- | 45 | 0x2d | 00101101
. | 46 | 0x2e | 00101110
/ | 47 | 0x2f | 00101111
0 | 48 | 0x30 | 00110000
1 | 49 | 0x31 | 00110001
2 | 50 | 0x32 | 00110010
3 | 51 | 0x33 | 00110011
4 | 52 | 0x34 | 00110100
5 | 53 | 0x35 | 00110101
6 | 54 | 0x36 | 00110110
7 | 55 | 0x37 | 00110111
8 | 56 | 0x38 | 00111000
9 | 57 | 0x39 | 00111001
<snip>
p | 112 | 0x70 | 01110000
q | 113 | 0x71 | 01110001
r | 114 | 0x72 | 01110010
s | 115 | 0x73 | 01110011
t | 116 | 0x74 | 01110100
u | 117 | 0x75 | 01110101
v | 118 | 0x76 | 01110110
w | 119 | 0x77 | 01110111
x | 120 | 0x78 | 01111000
y | 121 | 0x79 | 01111001
z | 122 | 0x7a | 01111010
{ | 123 | 0x7b | 01111011
| | 124 | 0x7c | 01111100
} | 125 | 0x7d | 01111101
~ | 126 | 0x7e | 01111110
Let me know if you have any questions about the logic.
You could create a function which takes a void pointer and the size of the structure as input.
void printdata(void *data, size_t len)
{
char my_char;
for (size_t m = 0; m < len; m++)
{
my_char = *(((char*) data) + m);
for (size_t i=0; i<8; i++)
{
if (i==4) printf(" "); // separate every four characters
printf("%d", (my_char & bitmask) != 0);
bitmask = bitmask >> 1;
}
printf("\n");
}
}
Then you can call this function for each element of your struct.
e.g.
typedef struct
{
int a;
char b;
int c[20];
}my_struct_t;
my_struct_t mystruct;
..
printdata(mystruct.a,sizeof(int));
printdata(mystruct.b,sizeof(char));
printdata(mystruct.c, 20*sizeof(int));
You can also pass the entire struct to the above function, but it will also print the padding bytes which is not what is needed.
This fit types what you want
#include <stdio.h>
#include <stdlib.h>
#define bitmask 0b1
void F1(void *a,int Len){
int i,j;
unsigned char*b=(unsigned char*)a;
b+=Len-1;
for(i=0;i<Len;i++,b--){
for(j=7;j>-1;j--){
printf("%d",((*b)&bitmask<<j)>>j);
}
}
printf("\n");
}
int main(){
unsigned int Q=10;
F1(&Q,sizeof(unsigned int));
unsigned short QQ=10;
F1(&QQ,sizeof(unsigned short));
unsigned char QQQ=10;
F1(&QQQ,sizeof(unsigned char));
return 0;
}
I've this array below:
dataIn[5] = 0x88;
dataIn[6] = 0x2A;
dataIn[7] = 0xC7;
dataIn[8] = 0x2B;
dataIn[9] = 0x00;
dataIn[10] = 0x28;
I need to convert those values to decimal because after that I need to convert the decimal values into ASCII and send to UART.
Eg:
| Hexa | Decimal | ASCII (I need to send this data to UART)
| 0x882AC72B00 | 584 833 248 000 | 35 38 34 38 33 33 32 34 38 30 30 30
| 0x5769345612 | 375 427 192 338 | 33 37 35 34 32 37 31 39 32 33 33 38
My problem: Those data should put all together and convert to decimal, but my compiler is just for 4 bytes and I don't know how to do this because I've 5 or more bytes ever.
Ps.: I'm using PIC18F46K80 and C18 compiler
[Edited]
Click here to see what happen when I try to use more than 4 bytes. This is my problem
Anyone could help me ?
Thanks in advance.
If I have understood well, first of all you should define a union like this:
typedef union _DATA64
{
uint64_t dataIn64;
uint8_t dataIn8[8];
}tu_DATA64;
and then copy the hex values in the previous defined union:
uint8_t i;
tu_DATA64 data;
...
data.dataIn64=0;
for(i=0; i<5; i++)
data.dataIn8[4-i]=dataIn[i];
now you have to convert the 64bit variable in a string using lltoa function, like suggested in this post:
char *str;
...
str=lltoa(data.dataIn64,10);
The str is the buffer string to send.
Have you considered writing your own conversion function? Here's a working example that can be adjusted to any length.
WARNING: My C skills are not the best!
#include <stdio.h>
/******************************************************************************/
void base10_ascii(unsigned char data[], int data_size, char ans[], int ans_size) {
char done;
do {
char r = 0;
done = 1;
for (int i=0; i<data_size; i++) {
int b = (r<<8) + data[i]; //previous remainder and current byte
data[i] = b / 10;
if (data[i] > 0) done = 0; //if any digit is non-zero, not done yet
r = b % 10;
}
for (int i=ans_size-1; i>0; i--) ans[i] = ans[i-1]; //bump up result
ans[0] = r + '0'; //save next digit as ASCII (right to left)
} while (!done);
}
/******************************************************************************/
int main(){
char outputBuffer[15] = {0};
char data[] = { 0x88, 0x2A, 0xC7, 0x2B, 0x00 }; //584833248000
base10_ascii(data,sizeof data,outputBuffer,sizeof outputBuffer);
printf("Output: %s\n",outputBuffer);
return 0;
}
I have a "C" program in my firestation that captures incoming packets to the station printer. The program then scans the packet and sends and audible alert for what apparatus is due on the call. The county recently started using UTF-8 packets and the c program can not deal with all the extra "00" in the data flow. I need to either ignore the 00 or set the program to handle UTF-8. I have looked for days and there is nothing concrete on how to handle utf-8 that a novice such as my self can handle. Below is the interpret part of the program.
72 00 65 00 61 00 74 00 68 00 69 00 6e 00 67 00 later in packet
43 4f 44 45 53 45 54 3d 55 54 46 38 0a 40 50 4a beginning of packet
***void compressUtf16 (char *buff, size_t count) {
int i;
for (i = 0; i < count; i++)
buff[i] = buff[i*2]; // for xx 00 xx 00 xx 00 ...
}*
{ u_int i=0;
char *searcher = 0;
char c;
int j;
int locflag;
static int locationtripped = 0;
static char currentline[256];
static int currentlinepos = 0;
static char lastdispatched[256];
static char dispatchstring[256];
char betastring[256];
static int a = 0;
static int e = 0;
static int pe = 0;
static int md = 0;
static int pulse = 0;
static char location[128];
static char type[16];
static char station[16];
static FILE *fp;
static int printoutscanning = 0;
static char printoutID[20];
static char printoutfileID[32];
static FILE *dbg;
if(pulse) {
if(pulse == 80) {
sprintf(betastring, "beta a a a");
printf("betastring: \"%s\"\n", betastring);
system(betastring);
pulse = 0;
} else
pulse++;
}
if(header->len > 96) {
for(i=55; (i < header->caplen + 1 ) ; i++) {
c = pkt_data[i-1];
if(c == 13 || c == 10) {
currentline[currentlinepos] = 0;
currentlinepos = 0;
j = strlen(currentline);
if(j && (j > 1)) {
if(strlen(printoutfileID) && printoutscanning) {
dbg = fopen(printoutfileID, "a");
fprintf(dbg, "%s\n", currentline);
fclose(dbg);
}
if(!printoutscanning) {
searcher = 0;
searcher = strstr(currentline, "INCIDENT HISTORY DETAIL:");
if(searcher) {
searcher = searcher + 26;
strncpy(printoutID, searcher, 9);
printoutID[9] = 0;
printoutscanning = 1;
a = 0;
e = 0;
pe = 0;
md = 0;
for(j = 0; j < 128; j++)
location[j] = 0;
for(j = 0; j < 16; j++) {
type[j] = 0;
station[j] = 0;
}
sprintf(printoutfileID, "calls/%s %.6d.txt", printoutID, header-> ts.tv_usec);
dbg = fopen(printoutfileID, "a");
fprintf(dbg, "%s\n", currentline);
fclose(dbg);
}
UTF-8, except for the zero code point itself, will not have any zero bytes in it. The first byte of all multi-byte encodings (non-ASCII code points) will always start with the 11 bit pattern, with subsequent bytes always starting with the 10 bit pattern.
As you can see from the following table, U+0000 is the only code point that can give you a zero byte in UTF-8.
+----------------+----------+----------+----------+----------+
| Unicode | Byte 1 | Byte 2 | Byte 3 | Byte 4 |
+----------------+----------+----------+----------+----------+
| U+0000-007F | 0xxxxxxx | | | |
| U+0080-07FF | 110yyyxx | 10xxxxxx | | |
| U+0800-FFFF | 1110yyyy | 10yyyyxx | 10xxxxxx | |
| U+10000-10FFFF | 11110zzz | 10zzyyyy | 10yyyyxx | 10xxxxxx |
+----------------+----------+----------+----------+----------+
UTF-16 will intersperse zero bytes between your otherwise ASCII bytes but it's then a simple matter of throwing away every second byte. Whether that's 0, 2, 4, ... or 1, 3, 5, ... depends on whether your UTF-16 encoding is big-endian or little-endian.
I see from your sample that your data stream does indicate UTF-8 (43 4f 44 45 53 45 54 3d 55 54 46 38 translates to the text CODESET=UTF8) but I'll guarantee you it's lying :-)
The segment 72 00 65 00 61 00 74 00 68 00 69 00 6e 00 67 00 is UTF-16 for reathing, presumably a word segment since I'm not familiar with that word (in English, anyway).
I would suggest you clarify with whoever is generating that data since it's clearly erroneous. As to how you process the UTF-16, I've covered that above. Provided it's ASCII data in there (the alternate bytes are always zero), you can just throw away those alternates with something like:
// Process a UTF16 buffer containing ASCII-only characters.
// buff is the buffer, count is the quantity of UTF-16 chars.
// Will change buffer.
void compressUtf16 (char *buff, size_t count) {
int i;
for (i = 0; i < count; i++)
buff[i] = buff[i*2]; // for xx 00 xx 00 xx 00 ...
}
And, if you're using the other endian UTF-16, simply change:
buff[i] = buff[i*2]; // for xx 00 xx 00 xx 00 ...
into:
buff[i] = buff[i*2+1]; // for 00 xx 00 xx 00 xx ...