While trying to implement the IKE session key generation algorithms I came across the following code snippets for the following algorithm implementation
Algorithm for generating a certain session key
SKEYID_e = HMAC (SKEYID, SKEYID_a || gxy || CKY-I || CKY-R || 2)
implementation to get the last concatenation HMAC of digit 2
hmac_update(ctx, (unsigned char *) "\2", 1)
here hmac_update is the API used to concatenate the buffer to get the HMAC before finalizing the digest and CTX is HMAC context "\2" is adding the digit 2 and 1 is size of the buffer.
My question is what is the difference between and escaped unsigned char * "\2" and a char/uint8_t value 2
The difference is that a char with numeric value 2 and the string "\2" is that the former is a char and the second is a literal representing a character array containing a char with numeric value 2 and then a char with numeric value 0. In other words:
(char)2 is a single character. Its type is char. Its value is 2.
"\2" is an array of characters. Its type decays to const char*. Its first entry is 2 and its second entry is 0.
Since hmac_update expects as its second argument a pointer to the bytes to use in the update, you can't provide 2 or (char)2 as an argument, since doing so would try to convert an integer to a pointer (oops). Using "\2" solves this problem by providing a pointer to the byte in question. You could also do something like this:
const char value = 2;
hmac_update(ctx, &value, 1);
"2" describes the character with the hex code 2 (which is a non-printable character, check http://ascii-table.com/info.php?u=x0002);
The digit "2" has the hex code 0x050 = 50, as is the printable character '2'.
Related
everyone!
please help me understand the following problem...
So i will have a STRING-type input of a note, looks like "A5" or "G#2" or "Cb4" etc. And i need to extract an octave index, which is the last digit "5" or "2" or "4"... And after exctraction i need it as an int-type.
So I did this:
string note = get_string("Input: ");
int octave = atoi(note[strlen(note) - 1]);
printf("your octave is %i \n", octave);
But it gave me an error "error: incompatible integer to pointer conversion passing 'char' to parameter of type 'const char *'; take the address with & [-Werror,-Wint-conversion]"
Then I tryied to throug away the math from the function, and did this:
int extnum = strlen(note) - 1;
int octave = atoi(note[extnum]);
It didn't work as well. So i did my reserch on atoi function and i don't get it...
ATOI expects a string (CHECK)
Converts it to an interger, not the ASCII meanning (CHECK)
Library for atoi function (CHECK)
What I am doing in basically asking "take n-th character of that string and make it an int".
After googling for some time a found an other code example where a guy uses atoi with this symbol '&'. So i did this:
int octave = atoi(¬e[strlen(note) - 1]);
And IT WORKED! But I can't understand WHY it worked with the & symbol and didnt work without it....Cause it always worked without it! There was a million times i was giving a single-character string like '5' or so ond just used atoi and it worked perfectly...
Plesase help me, why in this case it acts so weird?
C does not have a native string type. Strings are usually represented as char array or a pointer to char.
Assuming that string is just a typedef to char *.
if note is an array of chars, note[strlen(note)-1] is just the last character. Since atoi expects a pointer to char (which has to be null-terminated) you have to pass the address of the char and not the value.
The task to convert one char digit to int could also be solved easier:
int octave = note[strlen(note) - 1] - '0';
The function atoi takes a pointer to a character array as the input parameter (const char*). When you call note[strlen(note) - 1] this is a single character (char), in order to make atoi work you need to provide the pointer. You do that by adding & as you've done. This then works, because right after that single digit there is a null character \0 that terminates the string - because your original string was null-terminated.
Note however that doing something like this would not be a good idea:
char a = '7';
int b = atoi(&a);
as there is no way to be sure what the next byte in memory is (following the byte that belongs to a), but the function will try to read it anyway, which can lead to undefined behaviour.
The last character is... well a character! not a string. So by adding the & sign, you made it a pointer to character (char*)!
You can also try this code:
char a = '5';
int b = a - '0';
Gives you ASCII code of 5 minus ASCII code of 0
From the manual pages, the signature of atoi is: int atoi(const char *nptr);. So, you need to pass the address of a char.
When you do this: atoi(note[strlen(note) - 1]) you pass the char itself. Thus, invoking UB.
When you use the &, you are passing what the function expects - the address. Hence, that works.
atoi excepts a string (a pointer to character), not a single character.
However, you should never use atoi since that function has bad error handling. The function strtol is 100% equivalent but safer.
You need to do this in two steps:
Find the first digit in the string.
From there, convert it to integer by calling strtol.
1) can is solved by looping through the string, checking if every item is a digit by calling isdigit from ctype.h. Simultaneously, check for the end of the string, the null terminator \0. When you find the first digit, save a pointer to that address.
2) is solved by passing the saved pointer to strtol, such as result = strtol(pointer, NULL, 10);.
I had an issue where my C program allocated input data correctly only for values less than 5. I found the error in the creation of the int array holding the values: I had used atoi(var-1) instead of atoi(var)-1.
When var='5', atoi(var-1) is 0 when printed out. Why is the number "5" where the erroneous char to int conversion breaks? And why does it become zero at that point?
I'm just curious about what actually happens with this.
When you write atoi(var - 1), where var is a char*, you are asking the function atoi to read the string which begins at the memory location one lower than var and convert that to an integer.
In general, the character that is at the lower memory address could be anything. You just happened to have it break when your char* was '5', but it could have happened anywhere.
On the other hand atoi(var) - 1 does exactly what you would expect, converting var to an int and then subtracting 1 numerically.
Pointer arithmetic. If var is a string (char *), then var + n is the substring starting at offset n.
const char* s = "12345":
printf("%d\n", atoi(s + 2)); // prints 345
Subtraction is allowed as well: var - 1 is a pointer to one character before the string. This may be anything, but is probably a non-digit character, so atoi returns 0.
I'm still new to the forum so I apologize in advance for forum - etiquette issues.
I'm having trouble understanding the differences between int arrays and char arrays.
I recently wrote a program for a Project Euler problem that originally used a char array to store a string of numbers, and later called specific characters and tried to use int operations on them to find a product. When I used a char string I got a ridiculously large product, clearly incorrect. Even if I converted what I thought would be compiled as a character (str[n]) to an integer in-line ((int)str[n]) it did the exact same thing. Only when I actually used an integer array did it work.
Code is as follows
for the char string
char str[21] = "73167176531330624919";
This did not work. I got an answer of about 1.5 trillion for an answer that should have been about 40k.
for the int array
int str[] = {7,3,1,6,7,1,7,6,5,3,1,3,3,0,6,2,4,9,1,9};
This is what did work. I took off the in-line type casting too.
Any explanation as to why these things worked/did not work and anything that can lead to a better understanding of these ideas will be appreciated. Links to helpful stuff are as well. I have researched strings and arrays and pointers plenty on my own (I'm self taught as I'm in high school) but the concepts are still confusing.
Side question, are strings in C automatically stored as arrays or is it just possible to do so?
To elaborate on WhozCraig's answer, the trouble you are having does not have to do with strings, but with the individual characters.
Strings in C are stored by and large as arrays of characters (with the caveat that there exists a null terminator at the end).
The characters themselves are encoded in a system called ascii which assigns codes between 0 - 127 for characters used in the english language (only). Thus "7" is not stored as 7 but as the ascii encoding of 7 which is 55.
I think now you can see why your product got so large.
One elegant way to fix would be to convert
int num = (int) str[n];
to
int num = str[n] - '0';
//thanks for fixing, ' ' is used for characters, " " is used for strings
This solution subtracts the ascii code for 0 from the ascii code for your character, say "7". Since the numbers are encoded linearly, this will work (for single digit numbers). For larger numbers, you should use atoi or strtol from stdlib.h
Strings are just character arrays with a null terminating byte.
There is no separate string data type in c.
When using a char as an integer, the numeric ascii value is used. For example, saying something like printf("%d\n", (int)'a'); will result in 97 (the ascii value of 'a') being printed.
You cannot use a string of numbers to do numeric calculations unless you convert it to an integer array. To convert a digit as a character into its integer form, you can do something like this:
char a = '2';
int a_num = a - '0';
//a_num now stores integer 2
This causes the ascii value of '0' (48) to be subtracted from ascii value '2' (50), finally leaving 2.
char str[21] = "73167176531330624919"
this code is equivalent to
char str[21] = {'7','3','1','6','7','1','7','6','5',/
'3','1','3','3','0','6','2','4','9','1','9'}
so whatever stored in str[21] is not numbers, but the char(their ASCII equivalent representation is different).
side question answer - yes/no, the strings are automatically stored as char arrays, but the string does has a extra character('\0') as the last element(where a char array need not have such a one).
Just wondering if someone could explain this to me? I have a program that asks a user to input a sentence. The program then reads the user input into an array and changes all of the vowels to a $ sign. My question is how does the for loop work? When initialising char c = 0; does that not mean that the array element is an int? I can't understand how it functions.
#include <stdio.h>
#include <string.h>
int main(void)
{
char words[50];
char c;
printf("Enter any number of words: \n");
fgets(words, 50, stdin);
for(c = 0; words[c] != '\n'; c++)
{
if(words[c] =='a'||words[c]=='e'||words[c]=='i'||words[c]=='o'||words[c]=='u')
{
words[c] = '$';
}
}
printf("%s", words);
return 0;
}
The code treats c as an integer variable (in C, char is basically a very narrow integer). In my view it would be cleaner to declare it as int (perhaps unsigned int). However, given that words is at most 50 characters long, char c works fine.
As to the loop:
c = 0 initializes c to zero.
words[c] != '\n' checks -- right at the start and also after each iteration -- whether the current character (words[c]) is a newline, and stops if it is.
c++ increments c after each iteration.
An array is like a building, you have several floors each one with a number.
In the floor 1 lives John.
In floor 2 lives Michael.
If you want to go to Jonh apartment you press 1 on the elevator. If you want to go to Michael's you press 2.
Thats the same with arrays. Every position in the array stores a value, in this case a letter.
Every position has a index associated. The first position is 0.
When you want to access a position of the array you use array[position] where position is the index in the array that you want to access.
The variable c holds the position to be acessed. When you do words[c] you're acctualy accessing the cnt position in the array and retrieving its value.
Supose the word is cool
word[1] results in o,
word[0] results in c
To determine the end of the word, a the caracter \n is set at the last position of the array.
Not really, char and int are implicitly converted.
You can look at a char in this case as a smaller int. sizeof(char) == 1, so it's smaller than an int, that's probably the reason it was used. Programatically, there's no difference in this case, unless the input string is very long, in which case the char will overflow before an int does.
Number literals (such as 0 in your case) are compatible with variables of type char. In fact, even a character literal enclosed in single quotes (for example '\n') is of type int but is implicitly converted to a char when assigned or compared to another char.
Number literals are interchangeable with character literals, as long as the former do not exceed the range of a character.
The following should result in a compiler warning:
char c = 257;
whereas this will not:
char c = 127;
A char is C is an integral type as is short, int, long, and long long (and many other types):
It is defined as the smallest addressable unit on the machine you are compiling on and will usually be 8 bits which means it can hold values -128 to 127. And an unsigned char can hold values 0 - 255.
It works as an iterator in the above since it will stop before 50 all the time and it can hold values up to 127. Whereas an int type can usually hold values up to 2,147,483,647, but takes up 4 times the space in the machine as an 8 bit char. An int is only guaranteed to be at least 16 bits in C which means values between −32,768 and 32,767 or 0 - 6,5535 for an unsigned int.
So your loop is just accessing elements in your array, one after the other like words[0] at the beginning to look at the first character, then words[1] to look at the next character. Since you use a char, which I'm assuming is 8 bits on your machine as that is very common. Your char will be enough to store the iterator for your loop until it gets above 127. If you read in more than 127 characters (instead of just 50) and used a char to iterate you would run into weird problems since the char can't hold 128 and will loop around to -128. Causing you to access words[-128] which would most likely result in a Segmentation Fault.
I know my way around ruby pretty well and am teaching myself C starting with a few toy programs. This one is just to calculate the average of a string of numbers I enter as an argument.
#include <stdio.h>
#include <string.h>
main(int argc, char *argv[])
{
char *token;
int sum = 0;
int count = 0;
token = strtok(argv[1],",");
while (token != NULL)
{
count++;
sum += (int)*token;
token = strtok(NULL, ",");
}
printf("Avg: %d", sum/count);
printf("\n");
return 0;
}
The output is:
mike#sleepycat:~/projects/cee$ ./avg 1,1
Avg: 49
Which clearly needs some adjustment.
Any improvements and an explanation would be appreciated.
Look for sscanf or atoi as functions to convert from a string (array of characters) to an integer.
Unlike higher-level languages, C doesn't automatically convert between string and integral/real data types.
49 is the ASCII value of '1' char.
It should be helpful to you....:D
The problem is the character "1" is 49. You have to convert the character value to an integer and then average.
In C if you cast a char to an int you just get the ASCII value of it. So, you're averaging the ascii value of the character 1 twice, and getting what you'd expect.
You probably want to use atoi().
EDIT: Note that this is generally true of all typecasts in C. C doesn't reinterpret values for you, it trusts you to know what exists at a given location.
strtok(
Please, please do not use this. Even its own documentation says never to use it. I don't know how you, as a Ruby programmer, found out about its existence, but please forget about it.
(int)*token
This is not even close to doing what you want. There are two fundamental problems:
1) A char* does not "contain" text. It points at text. token is of type char*; therefore *token is of type char. That is, a single byte, not a string. Note that I said "byte", not "character", because the name char is actually wrong - an understandable oversight on the part of the language designers, because Unicode did not exist back then. Please understand that char is fundamentally a numeric type. There is no real text type in C! Interpreting a sequence of char values as text is just a convention.
2) Casting in C does not perform any kind of magical conversions.
What your code does is to grab the byte that token points at (after the strtok() call), and cast that numeric value to int. The byte that is rendered with the symbol 1 actually has a value of 49. Again, interpreting a sequence of bytes as text is just a convention, and thus interpreting a byte as a character is just a convention - specifically, here we are using the convention known as ASCII. When you hit the 1 key on your keyboard, and later hit enter to run the program, the chain of events set in motion by the command window actually passed a byte with the value 49 to your program. (In the same way, the comma has a value of 44.)
Both of the above problems are solved by using the proper tools to parse the input. Look up sscanf(). However, you don't even want to pass the input to your program this way, because you can't put any spaces in the input - each "word" on the command line will be passed as a separate entry in the argv[] array.
What you should do, in fact, is take advantage of that, by just expecting each entry in argv[] to represent one number. You can again use sscanf() to parse each entry, and it will be much easier.
Finally:
printf("Avg: %d", sum/count)
The quotient sum/count will not give you a decimal result. Dividing an integer by another integer yields an integer in C, discarding the remainder.
In this line: sum += (int)*token;
Casting a char to an int takes the ASCII value of the char. for 1, this value is 49.
Use the atoi function instead:
sum += atoi(token);
Note atoi is found in the stdlib.h file, so you'll need to #include it as well.
You can't convert a string to an integer via
sum += (int)*token;
Instead you have to call a function like atoi():
sum += atoi (token);
when you cast a char (which is what *token is) to int you get its ascii value in C - which is 49... so the average of the chars ascii values is in fact 49. you need to use atoi to get the value of the number represented