This is written in 'c' and compiled with gcc. I'm not sure what else you need to know.
The smallest complete example I could put together is shown here. The variable 'numatoms' loses its value when it gets to line 23 (after the scanf()).
I'm stumped. Maybe it has something to do with scanf() overwritting the space for numatoms?
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
/*
*
*/
int main(int argc, char** argv) {
uint8_t numatoms;
uint8_t r;
char a[20];
do {
printf("NO. OF ATOMS?");
fflush(stdout);
scanf("%d", &numatoms);
printf("\r\n");
for(;;){
printf("value of numatoms is %u\r\n", numatoms);
printf("RAY?");
fflush(stdout);
scanf("%u", &r);
printf("value of numatoms is %u\r\n", numatoms);
if(r < 1)
break;
else {
printf("value of numatoms is %u\r\n", numatoms);
}
}
printf("CARE TO TRY AGAIN?");
fflush(stdout);
scanf("%s", a);
printf("\r\n");
} while (a[0] == 'y' || a[0] == 'Y');
return (EXIT_SUCCESS);
}
uint8_t is 8 bits long %u reads an unsigned int (probably 32 bits long).
You either need to make numatoms "bigger" (i.e. unsigned int) or read the correct size (see scanf can't scan into inttypes (uint8_t))
You should use macros for format specifiers for integer types defined in the header <inttypes.h>.
From the C Standard (7.8.1 Macros for format specifiers)
1 Each of the following object-like macros expands to a character
string literal containing a conversion specifier, possibly modified by
a length modifier, suitable for use within the format argument of a
formatted input/output function when converting the corresponding
integer type. These macro names have the general form of PRI
(character string literals for the fprintf and fwprintf family) or SCN
(character string literals for the fscanf and fwscanf family),217)
followed by the conversion specifier, followed by a name corresponding
to a similar type name in 7.20.1. In these names, N represents the
width of the type as described in 7.20.1.
The general form of the macro used for unsigned integer types with the conversion specifier u looks like
SCNuN
Here is a demonstrative program
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main(void)
{
uint8_t x;
scanf( "%" SCNu8, &x );
printf( "x = %u\n", x );
return 0;
}
Related
I am trying to convert a series of decimal numbers to their hex representation in string format and then back from string to decimal. This might sound strange but is a simplified representation of a more complex situation.
So, either way, I have the following piece of code which almost works fine. For some reason my variable a is still equal to 0 at the end while it should equal 43, all the other variables seem to be alright:
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
/********************* A *******************/
uint16_t a = 43; //0x002b
int16_t b = -43; //0xffd5
uint32_t c = 234; //0x000000ea
int32_t d = -234; //0xffffff16
char aStr[10]={0};
char bStr[10]={0};
char cStr[10]={0};
char dStr[10]={0};
snprintf(aStr, sizeof(aStr), "%04hhx", a);
snprintf(bStr, sizeof(bStr), "%04x", b & 0xFFFF);
snprintf(cStr, sizeof(cStr), "%08hhx", c);
snprintf(dStr, sizeof(aStr), "%08x", d & 0xFFFFFFFF);
fprintf(stdout, "TX a = %s.\n", aStr);
fprintf(stdout, "TX b = %s.\n", bStr);
fprintf(stdout, "TX c = %s.\n", cStr);
fprintf(stdout, "TX d = %s.\n", dStr);
/********************* B *******************/
uint16_t aOut = 0;
int16_t bOut = 0;
uint32_t cOut = 0;
int32_t dOut = 0;
sscanf(aStr, "%04hhx", &aOut);
sscanf(bStr, "%04x", &bOut);
sscanf(cStr, "%08hhx", &cOut);
sscanf(dStr, "%08x", &dOut);
fprintf(stdout, "rx a = %d\n", aOut); //<---- this line prints 0 for a. Why?
fprintf(stdout, "rx b = %d\n", bOut);
fprintf(stdout, "rx c = %d\n", cOut);
fprintf(stdout, "rx d = %d\n", dOut);
return 0;
}
Does anybody know why or what I am missing?
The line
sscanf(aStr, "%04hhx", &aOut);
is wrong. The %hhx conversion format specifier requires an argument of type unsigned char *, but you are instead passing it an argument of type uint16_t *. This invokes undefined behavior.
I suggest that you change that line to the following:
sscanf(aStr, "%04"SCNx16, &aOut);
On most platforms, the macro SCNx16 will simply expand to "hx", but it is generally safer to use the macro, in case you code happens to be running on a (future) platform on which uint16_t is not equivalent to an unsigned short.
The lines
sscanf(bStr, "%04x", &bOut);
sscanf(cStr, "%08hhx", &cOut);
sscanf(dStr, "%08x", &dOut);
are also using the wrong conversion format specifiers. I recommend that you use the following code instead:
sscanf(bStr, "%04"SCNx16, &bOut);
sscanf(cStr, "%08"SCNx32, &cOut);
sscanf(dStr, "%08"SCNx32, &dOut);
Strictly speaking, the above code also invokes undefined behavior, because the %x conversion format specifier requires a pointer to an unsigned type instead of to a signed type. However, this should not be a problem in practice, provided that the converted value can be represented both in the signed type and in the unsigned type.
PVS-Studio gave me a warning about this :
char c;
sscanf(line, "%d", &c);
I changed %d to %c but this created a bug because "c" now contains the ASCII value of the number and not the decimal one, so I went back to "%d".
So what's the correct specifier to ? is there another solution ?
c is a char. You asked to scan an int. PVS-Studio did right in warning you. Change the type of c to int and scan for a %d.
There are multiple solutions for your problem:
you can specify the correct destination type:
char c;
if (sscanf(line, "%hhd", &c) == 1) {
/* successful conversion */
...
}
you can use an intermediary variable:
char c;
int cc;
if (sscanf(line, "%d", &cc) == 1) {
/* successful conversion */
c = cc;
...
}
you can use different conversion function:
#include <stdlib.h>
...
char c;
c = atoi(line); // no error handling, return 0 if not a number
Note however that in all cases, if the numeric value converted by sscanf() or atoi() is outside the range of type char, the behavior is undefined. Most current system will just use the low order byte of the conversion result, but the C Standard does not guarantee it.
For example, I want to separate the string "0013subdivision" into 0013 (as an integer that can do addition, subtraction, etc. not char) and subdivision (as a char itself) in the given string.
This is my code so far:
#include <stdio.h>
#include <stdlib.h>
char location[10]; /* for the input with number and letter */
char x;
int house[10]; /* for the integer that will be separated from the string */
int main()
{
printf("Input: ");
scanf ("%s", &location[x]);
x=0
for (x=0; location[x]!='\0'; x++ );
return 0;
}
Based on my research, the code atoi is used to convert the converted value back to int (if I'm not mistaken) but I don't know when to place the function.
location is char array, if you are reading as string use only %s with string name only, index not required.
scanf ("%s", &location[x]); --> scanf ("%s", location);
After separating only int from char array you need to store one int value into house.
int house[10] --> int house.
Here is the code for extracting only int from string :
char location[10]; /* for the input with number and letter */
int x;
int house = 0 ; /* for the integer that will be separated from the string */
int main()
{
printf("Input: ");
//scanf ("%s", &location[x]);
scanf ("%s", location);
for (x=0; location[x]!='\0'; x++ ) {
if(location[x]>='0' && location[x]<='9') {
house =(house * 10) + (location[x]-48);
}
}
printf("int part = %d \n",house);
return 0;
}
The main problem in the code is
scanf ("%s", &location[x]);
Where you did not impose any limit on the scanning. An input like 0013subdivision will cause out of bound memory access leading to undefined behavior.
Always limit the input size with the length modifier, like, for an array defined as
char location[10]
use the conversion specification like
scanf ("%9s", location); // (i) one element saved for terminating null
// (ii) the array name decays to the pointer to 1st element
//in case of an argument to a function call.
Then, you don't need an integer array to store the extracted integer. A singular variable would suffice.
However, i'd like to suggest a much robust way:
read the user input using fgets()
then, scan the input using sscanf() and appropriate conversion specifier, like %4d%9s or alike.
The most correct way to do this is to use the strto... family of functions from stdlib.h. For example:
printf("%ld\n", strtol(str, NULL, 10));
The atoi family of functions should never be used for any purpose, since they have broken error handling and can be 100% replaced by the strto... functions.
You could use the scanf family of functions but they are needlessly slow and notoriously dangerous, so I don't really see the point of using them here.
If you are interested in implementing the actual copying manually, for learning purposes, it is fairly trivial:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int main (void)
{
const char str[] = "0013subdivision";
char number_part [sizeof(str)];
char letter_part [sizeof(str)];
size_t i;
for(i=0; str[i]!='\0' && isdigit(str[i]); i++) // find where the letters start
{}
memcpy(number_part, &str[0], i); // copy digit part
number_part[i] = '\0'; // append null terminator
memcpy(letter_part, &str[i], sizeof(str)-i); // copy letter part + null term
puts(number_part);
puts(letter_part);
printf("%ld\n", strtol(str, NULL, 10));
}
If the string is a run-time variable, you have to use strlen(str)+1 instead of sizeof().
strtol converts string to number and also gives you back the character it stopped on, i.e. first character after number.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
const char* const input = "0013subdivision";
const char* string;
const long number = strtol(input, &string, 10);
printf("Number: %ld String: '%s'\n", number, string);
// Number: 13 String: 'subdivision'
return 0;
}
https://repl.it/repls/SphericalImpracticalTinamou
I need to convert uint16_t value to a string. I want the string to be a decimal respresentation of the number.
Example: uint16_t i=256 string: 256
I tried with itoa(i,string, 10) but when i value increases starts printing negative values.
I send the string via the Serial Port.(UART)
It is there some alternative?
Use sprintf with %u format for unsigned int:
uint16_t i = 33000;
sprintf(str, "%u", i);
You can try to use sprintf() for common "to string" conversions. For example:
#include <stdio.h>
#include <math.h>
int main() {
uint16_t i = 256;
char str[80];
int str_len = sprintf(str, "%d", i);
return(0);
}
For more info look at this article.
I'm trying to learn some of the basics of C and I have been reading nonstop about gets/fgets/puts/scanf and can't seem to get this right...
My code is:
#include <string.h>
#include <stdio.h>
#define BUFF 256
void main()
{
char s[BUFF];
fgets(s, BUFF, stdin);
s[strlen(s)-1]='\0';
printf("%x %s %d", s, s, strlen(s));
}
I'm trying to get the hex format of the variable s to print, my input is AAAA and the output I want is 41414141 AAAA 4, the output I'm getting is 12fe80 AAAA 4.
I thought I needed to cast s (as a u int) for the hex interpretation, but that didn't work either.
I would really appreciate an explanation on this as well as help, I'm really trying to learn this.
Thank you!
void main()
This isn't your problem, but the correct definition is
int main(void)
void main() is useful mostly as a tool to detect C textbooks written by incompetent authors.
printf("%x %s %d", s, s, strlen(s));
This has undefined behavior:
"%x" requires an argument of type unsigned int; you're giving it a char* (the array expression s is converted to a pointer to its first element).
%d requires an argument of type int; you're giving it a size_t. Either convert it to int, or use %zu.
If you want to print a hexadecimal representation of the contents of the string s, there's no direct way to do that. You'll just have to loop over the characters contained in s and print the value of each one in hexadecimal. (You should cast each char value to unsigned int so it works properly with the "%02x" format.)
%x works on numbers. You're passing in a pointer to a string. So in this case printf() is interpreting the pointer (memory address) as a number and printing that address in hex format. Sounds like you just want to print the ASCII values, in hex, of each character in the input:
for (int i = 0; i < strlen(s); ++i)
printf("%02x", (unsigned) s[i]);
Try this
$ cat hello.c
#include <string.h>
#include <stdio.h>
#define BUFF 256
int main()
{
int i = 0; /* a counter */
char s[BUFF];
fgets(s, BUFF, stdin);
s[strlen(s)-1]='\0';
while (i < strlen(s)) { /* to get the character(s) in s */
printf("%x", s[i]); /* as hex */
i++;
}
printf(" %s %d\n", s, strlen(s)); /* as before */
}
$ gcc hello.c -o hello && echo "AAAA" | ./hello
41414141 AAAA 4
The hex value you are printing is the address of the string, not the contents (since s is a char*).
To see the full contents of the string as hex bytes, you will have to do something like this:
int n = strlen(s);
for(int ii=0; ii<n; ii++) printf("%02x", (unsigned int) s[ii]);
#include <stdio.h>
#include <string.h>
main() {
char a[]="AAAA";
printf("%x%x%x%x %s %d", a[0],a[1],a[2],a[3],a, (int)strlen(a));
}
print all the array index one by one.
printf("%x ", *s);
printf("%x ", *(s+1));
....
....