What is this part of the code doing? - c

I am new to c programming. As a part of my uni course for network security, I have to design a SSL handshake simulation. I found a sample code online, however i don't understand some parts of the code. Could you please help me with following :
What does (char) 0 do ?? ( send_data is defined as char send_data[1024]; )
send_data[0] = (char) 0; //Packet Type = hello
send_data[1] = (char) 3; //Version
EDIT + FOLLOWUP
Folks I know what type casting is.
I understand what casting is But the code I posted is doing nothing. Even though integer 0 is being cast as a character, its not doing anything because when you print it - its a blank - no value.
eg :
#include <stdio.h>
#include <stdlib.h>
int main(){
char test;
int num;
num = 1;
test = (char) num; // this does nothing
printf("num = %d , %c\n",num,num);
printf("test = %d , %c\n",test,test);
// Isn't this the correct way to do it ?? :
num = 3;
test = '3'; // now this is a character 3
printf("num = %d , %c\n",num,num);
printf("test = %d , %c\n",test,test);
return 0;
}
the output of above code is :
num = 1 ,
test = 1 ,
num = 3 ,
test = 51 , 3
So why is it being done ?? isn't this the right way to do it :- send_data[0] = '0'; send_data[1] = '3';

It simply casts the int 0 (or 3) into a char type.
It's possibly not necessary but may be used to remove warnings of possible truncation.
A better idiom would be:
send_data[0] = '\x00'; // Packet Type = hello
send_data[1] = '\x03'; // Version
since those are explicitly characters, without having to worry about casting.
Keep in mind that (char) 0 (or '\x00') is not the same as '0'. The former two give you the character code 0 (the NUL character in ASCII), the latter gives you the character code for the printable 0 character (character code 48 or '\x30' in ASCII). That's why your printing isn't acting as you seem to expect.
Whether your particular protocol requires code point 0 or printable character 0 is something you haven't made clear. If you're truly trying to emulate SSLv3, the correct values are the binary rather than printable ones as per RFC6101:
enum {
hello_request(0), client_hello(1), server_hello(2),
certificate(11), server_key_exchange (12),
certificate_request(13), server_done(14),
certificate_verify(15), client_key_exchange(16),
finished(20), (255)
} HandshakeType;

It is just casting the literal symbol into a char value. But I don't think it is necessary.

It is casting the int value into the char type.

This is known as type-conversion or casting. You do this when you need to change an entity of one data-type to another.
In your examples, 0 and 3 (integers) are being casted as type chars.
http://en.wikipedia.org/wiki/Type_conversion

send_data is defined as an array of char. But 0 and 3 are integer literals. When the integers are assigned to the array, they are being cast as char. This means that send_data [0] will hold the character with ASCII value 0, i.e. the NUL character. send_data[1] will hold the character with ASCII value 3, the end of text character.

int main()
{
char ch;
ch = (char) 0;
printf("%d\n", ch); //This will print 0
printf("%c\n", ch); //This will print nothing (character whose value is 0 which is NUL)
ch = (char) 3;
printf("%d\n", ch); //This will print 3
printf("%c\n", ch); //This will print a character whose value is 3
return 0;
}
It is type casting int type to char type.
Its good to create a demo program and test it when you get some doubts while reading.

Related

NUL character and static character arrays/string literals in C

I understand that strings are terminated by a NUL '\0' byte in C.
However, what I can't figure out is why a 0 in a string literal acts differently than a 0 in an char array created on the stack. When checking for NUL terminators in a literal, the zeros in the middle of the array are not treated as such.
For example:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
int main()
{
/* here, one would expect strlen to evaluate to 2 */
char *confusion = "11001";
size_t len = strlen(confusion);
printf("length = %zu\n", len); /* why is this == 5, as opposed to 2? */
/* why is the entire segment printed here, instead of the first two bytes?*/
char *p = confusion;
while (*p != '\0')
putchar(*p++);
putchar('\n');
/* this evaluates to true ... OK */
if ((char)0 == '\0')
printf("is null\n");
/* and if we do this ... */
char s[6];
s[0] = 1;
s[1] = 1;
s[2] = 0;
s[3] = 0;
s[4] = 1;
s[5] = '\0';
len = strlen(s); /* len == 2, as expected. */
printf("length = %zu\n", len);
return 0;
}
output:
length = 5
11001
is null
length = 2
Why does this occur?
The variable 'confusion' is a pointer to char of a literal string.
So the memory looks something like
[11001\0]
So when you print the variable 'confusion', it will print everything until first null character which is represented by \0.
Zeroes in 11001 are not null, they are literal zeroes since it is surrounded with double quotes.
However, in your char array assignment for variable 's', you are assigning a decimal value 0 to
char variable. When you do that, ASCII decimal value of 0 which is ASCII character value of NULL character gets assigned to it. So the the character array looks something like in the memory
[happyface, happyface, NULL]
ASCII character happyface has ASCII decimal value of 1.
So when you print, it will print everything up to first NULL and thus
the strlen is 2.
The trick here is understanding what really gets assigned to a character variable when a decimal value is assigned to it.
Try this code:
#include <stdio.h>
int
main(void)
{
char c = 0;
printf( "%c\n", c ); //Prints the ASCII character which is NULL.
printf( "%d\n", c ); //Prints the decimal value.
return 0;
}
You can view an ASCII Table (e.g. http://www.asciitable.com/) to check the exact value of character '0' and null
'0' and 0 are not the same value. (The first one is 48, usually, although technically the precise value is implementation-defined and it is considered very bad style to write 48 to refer to the character '0'.)
If a '0' terminated a character string, you wouldn't be able to put zeros in strings, which would be a bit... limiting.

Why strlen() returning 2 or 1 everytime?

Why doesn't strlen() return an exact value?
For example, when I input 123 it returns 2. For 12345 it returns 1. Why?
#include<stdio.h>
#include<string.h>
int main()
{
long int ui,remainder,i=0,len;
char binary[20];
scanf("%ld",&ui);
while(ui!=0) {
remainder=ui%2;
binary[i]=(char)remainder;
printf("%d ",remainder);
ui=ui/2;
i++;
}
binary[i]='\0';
printf("len is %ld\n",strlen(binary));
for(i=len-1;i>=0;i--) printf("%d",binary[i]);
return 0;
}
strlen returns the length of an array of characters until it finds the character '\0' (with numeric value 0) in it. Your binary array is an array of characters, but you are treating them as integers as you're storing the numeric values 0 and 1. When calculating its length, strlen stops when it finds the first 0 you wrote.
To get the answer you need, change the binary definition to char binary[20] = { 0 };, save the remainder values as ASCII characters (binary[i] = '0' + (char)remainder;), and print them as characters printf("%c ",binary[i]);
The reason it isn't working is because of how you're using binary.
The strlen function is meant to operate on NULL terminated strings. But binary isn't treaded as a string, but as an array of bytes.
The strlen function searches until it find a null bytes, i.e. a byte with a value of 0. In the case of "123", the value 0 appears after two bytes. In the case of "12345", the value 0 appears after one byte. This explains the output you're getting.
Also, you're using len without initializing it. This leads to undefined behavior. You want to set it to i after you exit the while loop. You also need to change the format specifier for your first printf from %d to %ld since remainder is declared as a long int.
There are a few problems here binary is a char so it's '0' + value print it out that way as well;
#include<stdio.h>
#include<string.h>
int main()
{
long int ui,remainder,i=0,len;
char binary[20] = {0};
scanf("%ld",&ui);
if (ui==0) { binary[i] = '0'; i++; } // Special case for zero
while(ui!=0) {
remainder=ui%2;
binary[i]=(char)remainder + '0';
printf("%d ",remainder);
ui=ui/2;
i++;
}
binary[i]='\0';
printf("len is %ld %s\n",len = strlen(binary), binary);
for(i=len-1;i>=0;i--)
printf("%c",binary[i]);
return 0;
}
For my run below I got
32
0 0 0 0 0 1 len is 6 000001
100000

Can i assign a integer to a character pointer array?

int k=5;
char* result = (char *)malloc(100 * sizeof(char));
result[count] = k;
Considering the above code, if I print the contents of result[count] it prints smiley symbols. I tried like below,but of no use.
result[count]=(char)k;
Can anyone help me?
I am percepting that malloc(100*sizeof(char)) will create 100 blocks each of size of character contiguously. Please correct me if I am wrong?
I'll disregard all the fluff about arrays and malloc as it is irrelevant to the problem you describe. You seem to essentially be asking "What will this code print:"
char c = 5;
printf("%c", c);
It will print the symbol 5 in your symbol table, most likely a non-printable character. When encountering non-printable characters, some implementations choose to print non-standard symbols, such as smileys.
If you want to print the number 5, you have to use a character literal:
char c = '5';
printf("%c", c);
or alternatively use poor style with "magic numbers":
char c = 53; // don't write code like this
printf("%c", c);
It is a problem of character representation. Let's begin by the opposite first. A char can be promoted to an int, but if you do you get the representation of the character (its code). Assuming you use ASCII:
char c = '5';
int i = c; // i is now 0x35 or 53 ASCII code for '5'
Your example is the opposite, 5 can be represented by a char, so result[count] = k is defined (even if you should have got a warning for possible truncation), but ASCII char for code 5 is control code ENQ and will be printed as ♣ on a windows system using code page 850 or 437.
A half portable (not specified, but is known to work on all common architectures) way to do the conversion (int) 5 -> (char) '5' is to remember that code '0' to '9' are consecutive (as are 'A' to 'Z' and 'a to 'z'), so I think that what you want is:
result[count] = '0' + k;
First, let's clean up your code a bit:
int k=5;
char* result = malloc(100);
result[count] = k;
sizeof(char) is always equal to 1 under any platform and you don't need to cast the return of malloc() in C.
This said, as long as your count variable contains a value between 0 and 99, you're not doing anything wrong. If you want to print the actual character '5', then you have to assign the ASCII value of that character (53), not just the number 5. Also, remember that if that array of chars has to be interpreted as a string, you need to terminate it with '\0':
int k=5, i;
char* result = malloc(100);
for (i=0; i<98; i++) {
result[i] = ' ';
}
result[98] = 53;
result[99] = '\0';
printf("%s\n", result);
The elements in the array you're trying to allocate are all the size of a char, 1 byte. An int is 4 bytes thus your issues. If you want to store ints in an array you could do:
int result[100];
Followed by storing the value, but honestly from the way your questioned is posed I don't know if that's actually what you're trying to do. Try rephrasing the post with what you're trying to accomplish.
Are you trying to store 5 as a character?

Cast an int array to string, then print with printf, without allocating new memory

I thought I had this solved, but apparently, I was incorrect. The question is... what did I miss?
Assignment description:
You are to create a C program which fills an integer array with integers and then you are to cast it as a string and print it out. The output of the string should be your first and last name with proper capitalization, spacing and punctuation. Your program should have structure similar to:
main()
{
int A[100];
char *S;
A[0]=XXXX;
A[1]=YYYY;
...
A[n]=0; -- because C strings are terminated with NULL
...
printf("My name is %s\n",S);
}
Response to my submission:
You still copied memory cells to other, which is not expected. You use different space for the integer array as the string which does not follow the requirements. Please follow the instructions carefully next time.
My submission
Note that the first time I submitted, I simply used malloc on S, and copied casted values from A to S. The response was that I could not use malloc or allocate new space. This requirement was not in the problem description above.
Below was my second and final submission, which is the submission being referred to in the submission response above.
#include <stdio.h>
/* Main Program*/
int main (int arga, char **argb){
int A[100];
char *S;
A[0] = 68;
A[1] = 117;
/** etc. etc. etc. **/
A[13] = 115;
A[14] = 0;
// Point a char pointer to the first integer
S = (char *) A;
// For generality, in C, [charSize == 1 <= intSize]
// This is the ratio of intSize over charSize
int ratio = sizeof(int);
// Copy the i'th (char sized) set of bytes into
// consecutive locations in memory.
int i = 0;
// Using the char pointer as our reference, each set of
// bits is then i*ratio positions away from the i'th
// consecutive position in which it belongs for a string.
while (S[i*ratio] != 0){
S[i] = S[i*ratio];
i++;
}
// a sentinel for the 'S string'
S[i] = 0;
printf("My name is %s\n", S);
return 0;
}// end main
It looks like you've got the core idea down: the space for one integer will hold many chars. I believe you just need to pack the integer array "by hand" instead of in the for loop. Assuming a 4-byte integer on a little-endian machine, give this a shot.
#include <stdio.h>
int main()
{
int x[50];
x[0] = 'D' | 'u' << 8 | 's' << 16 | 't' << 24;
x[1] = 0;
char *s = (char*)x;
printf("Name: %s\n", s);
return 0;
}
It sounds like your professor wanted you to put 4 bytes into each int instead of having an array of n "1 byte" ints that you later condensed into 4 / sizeof(int) bytes using the while loop. Per Hurkyl's comment, the solution to this assignment would be platform dependent, meaning that it will differ from machine to machine. I'm assuming your instructor had the class ssh into and use a specific machine?
In any case, assuming you're on a little endian machine, say you wanted to type out the string: "Hi Dad!". Then a snippet of the solution would look something like this:
// Precursor stuff
A[0] = 0x44206948; // Hi D
A[1] = 0x216461; // ad!
A[2] = 0; // Null terminated
char *S = (char *)A;
printf("My string: %s\n", S);
// Other stuff

Store an integer in a char array

I am trying to store an integer in a char array. How can I do that? This is my approach (by casting it the int to a char) but it does not work. What am I missing?
#include <stdio.h>
int main(int argc, char** argv)
{
char cArray[10] = {};
// Store a character in the char array
cArray[5] = 'c';
printf("%c\n", cArray[5]);
// Store an integer in the char array
cArray[6] = (char) 0; // WHY DOES THIS NOT WORK???
printf("%c\n", cArray[6]);
}
Let's start with the basics.
For x86 architecture(assuming you use it) a char variable is stored in 1 byte and an int variable is stored in 4 bytes.
It is IMPOSSIBLE to store a random integer value in a char variable unless you have some compression schema and know that some integer values will not occur(no random!) in your program. No exceptions.
In your case, you want to store integers in a char array. There are four options:
1.If you want to store a random integer in this char array, then you should get the pointer to the index that you want to store the integer and cast it to an integer pointer and use it like that.
char mychars[10];
int * intlocation = (int*)(&mychar[5]);
*intlocation = 3632; // stores 3632
Beware that this will write to 4 bytes(4 char locations in your array) starting from the index you have specified. You should always check you are not going out of array.Also you should do the same casting for retrieving the value when needed.
2.If your values are between [0,255] or [-128,127] you can safely store your integers in a char since these ranges can be represented using a byte. Beware that char being signed or unsigned is implementation-dependent. Check this out!
mychars[5] = 54;
3.If your integer is just a digit, you can use the char representation of the digit.
mychars[5] = your_digit + 48; // 48 is the ascii code for '0'
4.If you want to store the string representation of your integer, then you should use itoa() and write each char of the resulting string to your array one by one. In that case, you should always check that you are not going out of array.
cArray[6] = (char) 0; // WHY DOES THIS NOT WORK???
printf("%c\n", cArray[6]);
This code attempts to print a character with the encoding 0; assuming ASCII, nothing will get displayed because there is no printable character associated with that code.
If you intend to store the ASCII code for the character '0' and print it, then you need to write
cArray[6] = 48; // same as writing cArray[6] = '0' (ASCII)
printf( "%c\n", cArray[6] );
This will print 0 to your console.
If, on the other hand, you want to store any arbitrary integer value1 to cArray[6] and display that value, then you need to use the %d conversion specifier:
cArray[6];
printf( "%d\n", cArray[6] );
1. That is, any integer that fits into the range of char, anyway
Normally, a computer exactly does what you tell it. The instruction DWIM (do what I mean) hasn't been invented yet.
cArray[6] = (char) 0; // WHY DOES THIS NOT WORK???
sets the index position 6, but
printf("%c\n", cArray[5]);
prints the index position 5.
I would like to add on to Seçkin Savaşçı's answer (in which you cast a char* pointer to somewhere in the char array to an int* pointer, allowing you to write an integer to the array by dereferencing the pointer).
You can also use bit-shifting:
#include <stdio.h>
int main() {
int first_int = 4892; // number larger than 127 (max. value of char)
int second_int = 99584; // same
// char array to hold two integers:
char array[8]; // ...assuming an integer size of 4 and char size of 1
// Now, assuming you are on a little endian system (in which the least
// significant bytes come first), you can add the two above integers to the
// array like so:
array[0] = first_int; // assigns first_int's least significant byte
array[1] = first_int >> 8; // assigns first_int's 2nd least significant byte
array[2] = first_int >> 16; // assigns first_int's 2nd most significant byte
array[3] = first_int >> 24; // assigns first_int's most significant byte
// repeat for second_int:
array[4] = second_int;
array[5] = second_int >> 8;
array[6] = second_int >> 16;
array[7] = second_int >> 24;
// You can now prove that this char array holds the two integers like this:
printf("First integer: %d\n", *((int *) array));
printf("Second integer: %d\n", *((int *) (array + 4)));
return 0;
}
On a big endian system you would first assign the most significant byte, and move on to the least significant bytes.
Replace
cArray[6] = (char) 0; // WHY DOES THIS NOT WORK???
printf("%c\n", cArray[5]);
By
cArray[6] = (char)51;
printf("%c\n", cArray[6]);
Should display '3'
I think you will understand your mistake... 0 as int does not represent the printable character '0', but the NULL termination string
51 as int represent the character '3'
You may use itoa(0,&cArry[6],10).
Use the correctly desired format specifier.
cArray[6] = (char) 0; does store an integer 0 into array element cArray[6]. Its the printf() that is fooling OP into thinking that did not work.
Using %c says OP wants the character that is encoded with a 0. (It usually not visible). Use %d to print the integer value of cArray[6].
printf("%d\n", cArray[6]);
You can add the ASCII value of 0 to the value you want to store digit into the character array.
For example if you want to store 0,1,...,9 into the character array A[10], you may use the following code.
for(j = 0; j<k; j++)
{
A[j] = j + '0'; // Same effect if you use A[j] = j + 0x30
}
This works only if the integer you want to store is less than 10. Otherwise you will have to extract the digits using modulo operator and store.

Resources