Why does printing ch[1] give 2? - c

#include <stdio.h>
int main()
{
union a
{
int i;
char ch[2];
};
union a z = { 512 };
printf("%d %d %d", z.i, z.ch[0], z.ch[1]);
}
Output:
512 0 2
Why does printing ch[1] give 2?

as you know, in a union all members start from the same place in memory.
so ch[2] starts from the same place as i. 512 = 0x00000200. So, in little endian, the first byte is 00 and the second is 02.

Your union has 4 bytes, and is assigned with 512, meaning you have
00:00:00:00-00:00:00:00-00:00:00:10-00:00:00:00
since 512 is a one with 9 zeros after it.
From here it's pretty easy to understand your prints.
As #Some programmer dude commented, this is due to how binary numbers look like + endianness.

Related

Buffer overrun issue reported by static code analysis tool

My piece of code:
void temp(char *source)
{
char dest[41];
for(int i = 0; i < 20; i++)
{
sprintf(&dest[i*2], "%02x", (unsigned int)source[i]);
}
}
When I run the static code analysis tool, I get the warning below:
On 19th iteration of the loop : This code could write past the end of the buffer pointed to by &dest[i * 2]. &dest[i * 2] evaluates to [dest + 38]. sprintf() writes up to 9 bytes starting at offset 38 from the beginning of the buffer pointed to by &dest[i * 2], whose capacity is
41 bytes.The number of bytes written could exceed the number of allocated bytes beyond that offset. The overrun occurs in stack memory.
My question is: since in every loop iteration, we are only copying 2 bytes (considering size of unsigned int on the machine is 2 bytes) from source to destination, where is the possibility of copying 9 bytes on the last iteration?
char can be signed, and is so by default in x86 compilers. On my computer
#include <stdio.h>
int main(void) {
printf("%02x\n", (unsigned int)(char)128);
}
prints ffffff80.
What you want to do is use format "%02hhx" and argument (unsigned char)c.

Getting too much zero while reading binary files in

I'm doing a program that read the whole binary file (in my case, a picture), reading 2 by 2 bytes and printing how many times each byte (from 0000h to FFFFh) appear in the file, but I'm having an issue regarding the quantity of zeros I'm capturing. Don't know exactly if it's a common case, but I'm feeling there's something wrong by allocating the array. There's something like:
bit occuurrences
0 62354
1 13
2 4
3 5
4 2
5 2
6 0
7 2
. .
. .
65535 0
What do you guys think I'm doing wrong?
Follow the code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
unsigned short int *n;
int cont=0;
long lsize,i,j;
FILE *arq=fopen("C:\\Users\\NB\\Documents\\Testes Allegro\\Trabalho PAQ\\imagens\\426.png","rb");
FILE *out=fopen("saida.csv","w");
fseek(arq,0,SEEK_END);
lsize=ftell(arq);
rewind(arq);
n=(unsigned short int*)malloc(sizeof(unsigned short int)*lsize);
fread(n,sizeof(short int),lsize,arq);
fprintf(out,"bit,quantidade\n");
for(i=0x0000;i<=0xffff;i++)
{
for(j=0;j<lsize;j++)
{
if(n[j]==i)
cont++;
}
fprintf(out,"%li,%d\n",i,cont);
printf("%li,%d-",i,cont);
cont=0;
}
fclose(arq);
fclose(out);
free(n);
return 0;
}
You are allocating short ints but measuring & reading bytes. Your array n will not work in the way you want. You will need to size n to lsize/2 times (+ an edge case for odd sizes) and adjust your loop accordingly.
Your looping is very inefficient too!

Why do I get these memory addresses?

I was wondering why I get these memory addresses in this simple program.
#include <stdio.h>
int main() {
char *a = "buffera";
char *b = "bufferbb";
printf("%p %p\n", a, b);
return 0;
}
Output I get is.
00403064 0040306C
Supposedly each character occupies one byte in memory (two hex numbers), then if the string a occupy 7 + 1 = 8 bytes in memory and the address of a starts at 0x00403064, then according to me it should end at 0x00403079 and not at 0x0040306B.
0043064 + 8 = 0040306C; I don't know where you get 00403079 from.
0x00403064 + 0x8 == 0x0040306C
Note that these numbers are in hexadecimal.
But either way, while these strings can't overlap, they don't need to be placed anywhere near each other in memory.

2 dimensional array in C language

I am passing a 2d array to a function to print the output, but the output I am getting is erroneous
function
void PrintArray(unsigned char mat[][4]){
int i, j;
printf("\n");
for(i = 0;i<4;i++){
for(j = 0;j<4;j++)
printf("%3x",mat[i][j]);
printf("\n");
}
printf("\n");
}
main function
int main(){
int i,j;
//static int c=175;
unsigned char state[4][4], key[4][4], expandedKey[176];
printf("enter the value to be decrypted");
for(i=0;i<4;i++)
for(j=0;j<4;j++)
scanf("%x",(unsigned int *)&state[j][i]);
PrintArray(state);
return 0;
}
expected output
1 5 9 c
2 6 0 d
3 7 a e
4 8 b f
actual output
h2o#h2o-Vostro-1015:~$ ./a.out enter the value to be decrypted 1 2 3 4 5 6 7 8 9 0 a b c d e f
1 5 9 c
0 0 0 d
0 0 0 e
0 0 0 f
I checked the method of passing 2d array, its correct I think, but not sure why m getting this output, kindly advise...
I'm going to go out on a limb and say that your problem lies here:
scanf("%x",(unsigned int *)&state[j][i]);
state[i][j] is sized to hold a single char, but you're telling scanf to treat it as a pointer to unsigned int; this likely means that scanf is overwriting adjacent array elements, since sizeof (unsigned int) is most likely greater than sizeof (char).
Change the declaration of the array from char to unsigned int in both main and PrintArray, and lose the cast in scanf.
The array passing is correct. However, the scanf function seems to overwrite some values to be 0 due to the variable type %x.
The data type specified by %x is "int" because %x is like %d (except that the input is hexadecimal). The data occupies 4 bytes (typically). So when the user enters a number, say, 1, four bytes 01 00 00 00 (assuming little-endianness on an Intel machine) will be written to memory instead of 1. The trailing 0s will erase some existing elements that are stored in the byte array, because in the byte array, each element is allocated only 1 byte.
Try the following code:
int main() {
int i,j;
//static int c=175;
unsigned char state[4][4], key[4][4], expandedKey[176];
printf("enter the value to be decrypted");
int tmp;
for(i=0;i<4;i++)
for(j=0;j<4;j++) {
scanf("%x", &tmp);
state[j][i] = (char)tmp;
}
PrintArray(state);

If I have to represent integers and char's in a single array, what would be an acceptable way to do this in C?

Can I declare an int array, then initialize it with chars? I'm trying to print out the state of a game after each move, therefore initially the array will be full of chars, then each move an entry will be updated to an int.
I think the answer is yes, this is permitted and will work because an int is 32 bits and a char is 8 bits. I suppose that each of the chars will be offset by 24 bits in memory from each other, since the address of the n+1'th position in the array will be n+32 bits and a char will only make use of the first 8.
It's not a homework question, just something that came up while I was working on homework. Maybe I'm completely wrong and it won't even compile the way I've set everything up?
EDIT: I don't have to represent them in a single array, as per the title of this post. I just couldn't think of an easier way to do it.
You can also make an array of unions, where each element is a union of either char or int. That way you can avoid having to do some type-casting to treat one as the other and you don't need to worry about the sizes of things.
int and char are numeric types and char is guaranteed smaller than int (therefore supplying a char where an int is expected is safe), so in a nutshell yes you can do that.
Yes it would work, because a char is implicitly convertible to an int.
"I think the answer is yes, this is permitted and will work because an int is 32 bits and a char is 8 bits." this is wrong, an int is not always 32 bits. Also, sizeof(char) is 1, but not necessarily 8 bits.
As explained, char is an int compatible type.
From your explanation, you might initially start with an array of int who's values are char, Then as the game progresses, the char values will no longer be relevant, and become int values. Yes?
IMHO the problem is not putting char into an int, that works and is built into the language.
IMHO using a union to allow the same piece of space to be used to store either type, helps but is not important. Unless you are using an amazingly small microcontroller, the saving in space is not likely relevant.
I can understand why you might want to make it easy to write out the board, but I think that is a tiny part of writing a game, and it is best to keep things simple for the rest of the game, rather than focus on the first few lines of code.
Let's think about the program; consider how to print the board.
At the start it could be:
for (int i=0; i<states; ++i) {
printf("%c ", game_state[i]);
}
Then as the game progresses, some of those values will be int.
The issue to consider is "which format is needed to print the value in the 'cell'?".
The %c format prints a single char.
I presume you would like to see the int values printed differently from ordinary printed characters? For example, you want to see the int values as integers, i.e. strings of decimal (or hex) digits? That needs a '%d' format.
On my Mac I did this:
#include <stdio.h>
#define MAX_STATE (90)
int main (int argc, const char * argv[]) {
int game_state[MAX_STATE];
int state;
int states;
for (states=0; states<MAX_STATE; ++states) {
game_state[states] = states+256+32;
}
for (int i=0; i<states; ++i) {
printf("%c ", game_state[i]);
}
return 0;
}
The expression states+256+32 guarantees the output character codes are not ASCII, or even ISO-8859-1 and they are not control codes. They are just integers. The output is:
! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? # A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y
I think you'd like the original character to be printed (no data conversion) when the value is the initial character (%c format), but you do want to see data conversion, from a binary number to a string of digit-characters (%d or a relative format). Yes?
So how would the program tell which is which?
You could ensure the int values are not characters (as my program did). Typically, this become a pain, because you are restricted on values, and end up using funny expressions everywhere else just to make that one job easier.
I think it is easier to use a flag which says "the value is still a char" or "the value is an int"
The small saving of space from using a union is rarely worth while, and their are advantages to having the initial state and the current move available.
So I think you end up with something like:
#include <stdio.h>
#define MAX_STATE (90)
int main (int argc, const char * argv[]) {
struct GAME { int cell_state; int move; char start_value } game_state[MAX_STATE];
enum CELL_STATE_ENUM { start_cell, move_cell };
int state;
int states;
for (states=0; (state=getchar())!= EOF && states<MAX_STATE; ++states) {
game_state[states].start_value = state;
game_state[states].cell_state = start_cell;
}
// should be some error checking ...
// ... make some moves ... this is nonsense but shows an idea
for (int i=0; i<states; ++i ) {
if (can_make_move(i)) {
game_state[states].cell_state = move_cell;
game_state[states].move = new_move(i);
}
}
// print the board
for (int i=0; i<states; ++i) {
if (game_state[i].cell_state == start_cell) {
printf("'%c' ", game_state[i].start_value);
} else if (game_state[i].cell_state == move_cell) {
printf("%d ", game_state[i].move);
} else {
fprintf(stderr, "Error, the state of the cell is broken ...\n");
}
}
return 0;
}
The move can be any convenient value, there is nothing to complicate the rest of the program.
Your intent can be made a little more clear my using int8_t or uint8_t from the stdint.h header. This way you say "I'm using a eight bit integer, and I intend for it to be a number."
It's possible and very simple. Here is an example:
int main()
{
// int array initialized with chars
int arr[5] = {'A', 'B', 'C', 'D', 'E'};
int i; // loop counter
for (i = 0; i < 5; i++) {
printf("Element %d id %d/%c\n", i, arr[i], arr[i]);
}
return 0;
}
The output is:
Element 0 is 65/A
Element 1 is 66/B
Element 2 is 67/C
Element 3 is 68/D
Element 4 is 69/E

Resources