I have a string that has 0111111100000000000000000000101
I wanted to convert this to hex, so I used the code below
int assembledHex;
sscanf(buffer, "%x", &assembledHex);
printf("this is the assembled hex %x\n",assembledHex);
but when I print it, it gives me 101. I thought sscanf can convert to hex from a string, what am I doing wrong and how can I fix it. The result I want is 0x3F800005
This is not checked or anything, and also quite slow, but it's a quick start:
unsigned int bin_to_int(const char *s) {
int i;
unsigned int result;
result = 0;
if (s[0] == '1') result++;
for (i = 1; i < strlen(s); i++) {
result <<= 1;
if (s[i] == '1') {
result++;
}
}
return result;
}
Your sscanf is reading the string as HEX, but the string is written in binary. You get "101" because int can only store the first 8 digits - each digit is 4 bits, so two digits=8 bits=1 byte, and 8 digits are 4 bytes, which is the size of int. So you actually store "00000101", buy printf does not print the leading zeroes so you get "101".
Related
I'm trying to make a function that takes an array of characters as an input, and outputs printable characters normally, and non-printable characters in hexadecimal (by turning these character into decimal using Extended ASCII, then turning that decimal number into hex).
For example:
"This morning is ßright"
should turn into:
"This morning is E1right"
since ß in Extended ASCII is 225, and that in hexadecimal is E1.
Here is what I attempted:
void myfunction(char *str)
{
int size=0;
for (int i = 0; str[i] != NULL; i++) size++; //to identify how many characters are in the string
for (int i = 0; i < size; i++)
{
if (isprint(str[i]))
{
printf("%c", str[i]); //printing printable characters
}
else
{
if (str[i] == NULL) break; //to stop when reaching the end of the string
printf("%02x", str[i]); //This is where I'm having an issue
}
}
}
This function outputs this:
"This morning is ffffffc3ffffff9fright"
how can I turn the non-printable characters into their hex value? and what is causing this function to behave in this way?
Thanks in advance!
You're seeing a couple of issues here. The first is that the char type on your machine (as on most) is signed, so when you have a char that is not ascii, it shows up as a negative number. This then sign extends to your int size before you print it as an unsigned hex value, so you get those ffffff strings you see.
If you mask it to 8 bits, you'll see the hex values more clearly. Use
printf("%02X", str[i] & 0xff); // X to use upper-case hex chars for clarity
and you'll get the output
This morning is C39Fright
Now you see the second problem, which is that ß is not an ascii character. It is unicode character #00DF, however, and when it is encoded in UTF-8 it shows up as the two-byte sequence C3 9F.
You have plenty of issues with your code.
for (int i = 0; str[i] != NULL; i++) size++; NULL is a pointer str[i] is char. You simply want to compare with zero which is a null character. null character is not the same as NULL pointer!!!
Same here: if (str[i] == NULL) break;
printf("%02x", str[i]); you use wron format to print char value as number. You should use hh size modifier. See how it works in the attached code.
Use the correct type for indexes or sizes - size_t instead of int
Your code is overcomplicated.
void myfunction(const char *str)
{
while(*str)
{
if (isprint(*str))
{
printf("%c", *str); //printing printable characters
}
else
{
printf("%02hhX", *str); //This is where I'm having an issue
}
str++;
}
}
int main(void)
{
char *str = "This morning is \xE1right";
myfunction(str);
}
https://godbolt.org/z/6jKWdr3rM
I am trying to write a small bit of code where i can scan a binary digit, like 00110011, and get this into an integer as a number. So 00110011 would be 51.
The code i made for this goes like this
int main()
{
unsigned char byte;
int d;
scanf("%8s", &byte);
d = byte;
printf("%d,%c",d, byte);
return 0;
}
This however, give me an output of 48. 00000001 also gives me 48 and so does anything else.
I know whats going wrong, it sees the string of zeros and ones as a single 0 and since its character is 0x30, or 0d48, it outputs 48. I wont to know if there is a way to get around this adn scan this in as the binary equivelent.
Your code does not work at all:
you scan up to 8 characters plus a null terminator, passing the address of a single byte variable: this has undefined behavior.
d = byte does not perform any conversion. the character '0' was read into byte and its ASCII value is stored into d, namely 48 as output by your program.
Furthermore, there is no standard conversion specifier for binary encoding in scanf(). Reading a string is a good approach, but you should pass a larger buffer and use a loop to convert to binary:
#include <ctype.h>
#include <stdio.h>
int main() {
char buf[100];
/* read a sequence of at most 99 binary digits into buf */
if (scanf(" %99[01]", buf) == 1) {
unsigned int d = 0;
/* convert the binary digits one at a time into integer d */
for (int i = 0; buf[i]; i++) {
d = (d << 1) | (buf[i] - '0');
}
/* print value as a number */
printf("%s -> %d\n", buf, d);
if (d == (unsigned char)d && isprint(d)) {
/* print value as a character if printable */
printf("%s -> %c\n", buf, d);
}
}
return 0;
}
You can also use strtoul() to convert a number expressed as a string of binary digits (or in any other base up to 36):
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
char buf[100];
/* read a sequence of at most 99 binary digits into buf */
if (scanf(" %99[01]", buf) == 1) {
unsigned long d = strtoul(buf, NULL, 2);
/* print value as a number */
printf("%s -> %lu\n", buf, d);
if (d == (unsigned char)d && isprint((unsigned char)d)) {
/* print value as a character if printable */
printf("%s -> %c\n", buf, (unsigned char)d);
}
}
return 0;
}
Note however that the behavior of strtoul() will differ from the first code: strtoul() will return ULONG_MAX on overflow, whereas the first example would just compute the low order bits of the binary string.
I found this simple function that should be easy to understand and it does the trick. Its a algorithm that follows how you would naturally do it in real life with a pen and paper however you're gonna need -lm when you compile it(the gcc command) to include the math library, however you can get around the pow() and include problems if you just do a for loop.
#include <stdio.h>
#include <math.h>
int todecimal(long bno){
int dno = 0, i = 0, rem;
while (bno != 0) {
rem = bno % 10;
bno /= 10;
dno += rem * pow(2, i);
++i;
}
return dno;
}
(i'm french, sorry for my bad english)
I don't know how to get an int from a char[], the patern of the char will be the same everytime : "prendre 2", "prendre 44", "prendre 710"...
I want to check if the pattern of the sentence is correct and get the integer.
I have try to do this, but as you see, the problem is i just can check if the integer is between 0-9 because I check only one char.
[...]
else if (est_prendre(commande)){
/* if the output is 1*/
int number = commande[8]- '0'
}
int est_prendre(char *commande){
int i;
char temp[9] = "";
char c = commande[8];
int num = c - '0';
for (i=0; i<8; i++){
temp[i] = commande[i];
}
if (strcmp ("prendre ", temp) == 0)
{
if ( /* num IS INTEGER? */)
{
return 1;
}
else
{
return 0;
}
} else {
return 0;
}
}
I expect if commande = "prendre 3", output of est_prendre is 1 because the pattern is correct
And after than to put the integer into the variable number.
Thank You!
Assuming that 'commande + 8' is a valid substring, what you need is atoi() function (ASCII to Integer). This function is widely documented, and you can easily find online its usage.
int number = atoi(commande+8);
Just remember that the substring terminates at the first non-digit character:
atoi("23") returns 23
atoi("51hh37") returns 51
atoi("z3456") returns 0
Note: atoi converts input string into integer, and you can use it if you are sure it fits expected input. So, if you expect to have either long integers or float values in your string you can use atol() (ASCII to long) or atof() (ASCII to float).
This is very basic, you should (re)read any reference/tutorial on C that you have used to learn the language.
You should just use the sscanf() standard function:
int value;
if (sscanf(commande, "prendre %d", &value) == 1)
{
... it was a match, the variable 'value' will be set to the number from the string
}
you can delete the (strange-looking) code that copies characters from commande to temp, and the temp variable too of course. Just inspect the commande string directly.
I'm currently doing the CS50 course, and I'm stuck on the credit problem. The idea is to make a program to verify cards due to their inbuilt checksum. The first step is to take every second digit and multiply it by 2, then add all the digits of the products together.
My code isn't finished, but I've set it up to print some intermediary steps just so I can see what's going on.
#include <stdio.h>
#include <string.h>
void checksum (char number[20]);
int main (void){
char *card;
printf("Please enter a card number:");
scanf("%s", card);
if (strlen(card) == 13 || strlen(card) == 16 || strlen(card) == 15) {
checksum(card);
}
else{
printf("Not a number. Please try again.\n");
main();
}
}
void checksum (char *number) {
int check = 0;
int digits = 0;
for(int i = 1; i < 17; i += 2){
printf("No%c\n", number[i]);
digits = (number[i] * 2);
printf("D%i\n", digits);
while (digits > 0) {
check += digits % 10;
printf("C%i\n", check);
digits = digits / 10;
}
}
}
I know the first part is far from perfect but it's the checksum function I'm concerned with at the moment. When it takes the second digit(5) everything is fine. But then when it's multiplied by 2 according to the next line, somehow the result is 106(?)
Can someone explain what's going on here?
terminal output
You read in a string, i.e. a sequence of characters, probably in ASCII format. So your input "1500150015001500" is actually a sequence of characters terminated by string terminating character 0x0, e.g. like { '1', '5', '0', .... '\0' }. A single character value like '1', when interpreted as an integral value, is represented by its ASCII code, which is 48 for '0', 49 for '1', ... , and 53 for '5'. Hence, an expression like char c = '5'; int digit = c*2 actually yields 106 for digit. To take character '5' as integral value 5, you could write int digit = (c - '0'), which is the same as if you wrote (53 - 48).
Without modifying your code to much, test what happens:
#include <stdio.h>
#include <string.h>
void checksum (char *number);
int main (void){
char card[30];
printf("Please enter a card number:");
scanf("%s", card);
if (strlen(card) == 13 || strlen(card) == 16 || strlen(card) == 15) {
checksum(card);
}
else{
printf("Not a number. Please try again.\n");
main();
}
}
void checksum (char *number) {
int check = 0;
int digits = 0;
for(int i = 1; i < strlen(number); i += 2){
printf("No%c\n", number[i]);
digits = ((number[i]-'0') * 2);
printf("D%i\n", digits);
while (digits > 0) {
check += digits % 10;
printf("C%i\n", check);
digits = digits / 10;
}
}
}
A couple of things:
char *card; scanf("%s", card); is not going to work. You need to either declare card as an array of fixed size (i.e. char card[20]), or use malloc to allocate memory for the pointer char *card;. If you choose the latter option you also need to use free on the memory when you're done with it.
In your function checksum, you need to convert the characters you read in the string card into numbers. If the character set on your system is ASCII, you can achieve this by subtracting the value 0x30 (i.e. the numeric value of the character '0') from each character in the string before performing arithmetic on it.
char number[20] in a function signature is pointless; see this question for more information. Since the array decays to a pointer to its first element when passed as a function argument, you may as well have char *number in the function signature.
I am trying to convert an integer(greater than 9 as below 9 it converts easily by the below process) to character. But after conversion I get some characters like '?'..below is the code:
#include <stdio.h>
int main(void) {
int i = 15;
char c;
c=i+'0';
printf("%c", c);
return 0;
}
output: ?
Expected output: 15
"15" are two characters. You would have to convert it digit by digit.
It won't work because you have two digit number. Such simple convertion will work for numbers 0-9 but not for greater. You can use itoa function. Example of use is in the link provided
Making a string from an integer is not possible directly, the reason why this works
int number = 2;
char character = number + '0';
fprintf(stdout, "%c\n", character);
is because '0' is the ascii value that represents the number 0 which is 48, and since they appear in order in the ascii table, adding the number to it will give you the ascii value of the number.
But 15 consists of 2 ascii values, a quick way to perform the conversion is to use an array, like this
char string[3];
int number;
int result;
number = 15;
result = snprintf(string, sizeof(string), "%d", number);
if (result >= sizeof(string))
fprintf(stdout, "the string was truncated, there is no space to store the result");
else if (result < 0)
fprintf(stderr, "an error occurred\n");
else
fprintf(stdout, "%s\n", string);
You have 2 digits which is why printing it out like that doesn't work. If you want to convert the int to a string use sprintf :
int i= 15;
char str[15];
snprintf(str, 15, "%d", i); // str now contains "15"