Need some assistance with understanding char->ASCII and some basics - c

I had a project to write this program that reads a character, integer and a floating number. It also had to convert the character in to its ASCII integer. I vaguely understand most of it except the code regarding the ASCII number. I created most of it on my own but when it came to converting the character I had a buddy help me, but he is not the best at explaining this.
Any explanation would be very helpful, thank you. I did this all by trial and error for... probably far too long :P
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char c;
int i;
float f;
printf ("Please enter a character: ");
scanf ("%c", &c);
printf ("Please enter an integer: ");
scanf ("%d", &i);
printf ("Please enter a floating point number: ");
scanf ("%f", &f);
printf ("\n");
printf ("The character you entered is: %c which is %d in integer-specification\n", c,c);
printf ("The integer you entered is: %d.\n", i);
printf ("The floating-point number you entered is: %f.\n", f);
return 0;
}

It will be helpful to have a reference documentation of printf handy.
When the format specifier is %c, printf expects an int. A char works since it is promoted to an int.
When the format specifier is %d, printf expects an int. A char works since it is promoted to an int.
For the first case, printf prints the character corresponding to the value of the int.
For the second case, printf just prints the number.

Essentially a char is just an integer with a range from 0 to 255, the only thing that makes it a 'character' is that we have assigned characters to be represented by certain numbers.
What's going on in the printf() is that first you tell it that you're going to pass a char and would it please just output that byte to be displayed, then you say that you want it to convert an integer to a string and output that.
What it boils down to is that the ASCII code is the character.
Note: for reasons that are not important at the moment when being passed into a vararg function like printf() chars and shorts are promoted to ints.

Here is my attempt at explaining this.
Everything in a program memory is stored as sequences of 0s and 1s (binary numbers). You are probably familiar with bits and bytes, but just in case: a binary digit (0 or 1) is a bit. A sequence of 8 bits is a byte. Characters, such as 'A', 'b', '1', etc. have to be stored as numbers in memory. There are different ways to map a character to a number: EBCDIC (very rare these days, was used on large mainframes in the old days), UTF-8, UTF-16, UTF-32 (types of Unicode), ASCII. These mappings are called character encodings, and ASCII is the simplest of those commonly used.
So, when you enter a character, it gets stored in the variable c as an integer number encoded using ASCII. The content of memory location corresponding to the variable can be thus viewed both as a character and an integer.
When using the printf() function you can request the same variable to be printed using different possible representations. In this case, since c is a character variable and can be represented as a character or a number, you can use the different format specifiers, %c and %d, to have it printed as character and integer, respectively.
The 1st of the printf() calls above takes 3 arguments. The first argument is a string that is printed out, with things that start with % being used to interpret the remaining arguments. %c corresponds to the 2nd argument, %d to the 3rd. %c says: "treat the 2nd argument as character and print it out." %s says: "treat the 3rd argument as integer and print it out."
The other 2 printf() calls in your code take only 2 arguments. The 1st argument, the string, contains only one thing starting with % (format specifier), so we only need 1 additional argument to be interpreted using the format specifier.
Hope this is helpful.

the Man ascii will make you understand

Related

Why is the output 6487620 (profit) by giving any input in this c program used to show profit or loss [duplicate]

#include <stdio.h>
#include <stdlib.h>
int main() {
char a;
printf("What? \t");
scanf("%s", &a);
printf("U have to %s", a);
return 0;
}
Whenever I build and run this code and enter a value in %s, I get an error and the debug program stops working and closes. But when I use ampersand sign like this:
#include <stdio.h>
#include <stdlib.h>
int main() {
char a;
printf("What? \t");
scanf("%s", &a);
printf("U have to %s", &a);
return 0;
}
in the printf... it works. Why is that? It also differs between the format specifier, such as one doesn't need to put & (ampersand) sign in printf when one uses %c or %d in the scanf. Why does this happen and is it related to the data types and which format specifiers concludes this result?
(sorry for my bad English. I am not a native English speaker and this is my first time here).
What you have here is a classic example of code that seems to work, but for the wrong reasons.
Let's review a few things about printf and scanf. The format specifier %d is for values of type int. You can read an integer like this:
int i;
scanf("%d", &i);
And you can print it back out like this:
printf("%d\n", i);
Why does one use an & and one does not? Well, C uses what's called "pass by value". If we wrote
scanf("%d", i); /* WRONG */
we would be passing the value of i to scanf. But we don't want to pass the (old) value of i to scanf, we want scanf to read a new value, and store it into i. In other words, we want scanf to, in effect, pass the new value of i back to us. For that to work, we instead pass scanf a pointer to the variable i where we want it to store the just-read integer. That's what the & does -- it generates a pointer to i.
When we call printf, on the other hand, the regular way of passing arguments works just fine. We do want to pass i's value to printf so that it can print it out. If we were to call
printf("%d\n", &i); /* WRONG */
it wouldn't work, because printf expects an int, and here we're wrongly handing it a pointer-to-int.
So now we've learned that for integers with %d, printf wants an int and scanf wants a pointer-to-int.
Let's talk about characters. The format %c is for characters. We can read one character with scanf:
char c;
scanf("%c", &c);
And we can print it with printf:
printf("%c\n", c);
Again, the pattern is exactly the same. scanf needs a pointer, so that it can fill in the value, so we pass &c. But printf just needs the value, so we pass plain c.
Now we get to strings. A string in C is an array of characters. Also strings in C are always terminated by a special null character, '\0', that marks the end of the string. So if we wanted to declare a variable that could contain strings up to 9 characters long, we might write
char s[10];
That gives us room for 9 characters, plus the terminating '\0'.
But arrays are special in C: Whenever you pass an array to a function, or whenever you do anything that would require the "value" of the array, what you get instead (what the compiler automatically generates for you) is a pointer to the array's first element.
What this means is that to read a string with scanf and %s, we can just call:
scanf("%s", s);
"But where is the &?", you ask. "I thought you always needed an & when calling scanf!"
Well, not quite. You always need a pointer when calling scanf. And in fact, when you called scanf("%s", s), it was just as if you had written
scanf("%s", &s[0]);
When you use %s with scanf, it expects a pointer to the first of several characters, that is, a pointer to the beginning of an array of characters, where it should begin writing the string it reads. (How does it know how big the array is? What if the user types a string that's too long to fit in the array? We'll get to those points in a moment.)
You can print strings with %s too, of course, and it looks like this:
printf("%s\n", s);
This is, again, just as if you had written
printf("%s\n", &s[0]);
When you use %s with printf, it expects a pointer to the first of several characters which it should begin printing, until it finds the terminating '\0' character.
So %s is special with printf and scanf, because strings are special (because arrays are special). With %d and %c and just about every other format specifier, you usually need a & when you call scanf, and you usually don't want that & when you call printf. But with %s, you usually don't want the & for either printf or scanf.
(And if we think about it a bit more carefully, the exception is not so much that scanf and %s does not need the &. Remember, the rule is really, scanf always needs pointers. The only reason scanf and %s doesn't need an & is that when you pass an array, you get a pointer to the array's first element automatically. So the exception is really for printf and %s: printf and %s does expect a pointer, and the reason printf and %s is designed to expect a pointer is that there's no way to not give it one: it has to accept a pointer, because for strings, that's what you always end up giving it.)
So the rule with %s is that scanf expects a pointer to the first of several characters, and printf expects a pointer to the first of several characters, too.
So now, with all that background out of the way, we can look at your code. You basically wrote
char c;
scanf("%s", &c);
At first this might seem to be kinda, sorta, almost correct. scanf and %s wants a pointer to a character, and you gave it &c, which is a pointer to a character. But %s really wants a pointer to the first of several characters. But you gave it a pointer to just a single character. So when the user types a string, the first character typed will get stored in c, but the rest of the characters, and the terminating '\0', will get written to unallocated memory somewhere off to the right of variable c. They'll overwrite ("clobber") memory that was, perhaps, used for something else. This is a serious problem, but it might not become evident right away.
Finally, you tried to print things out again with printf. You first tried
printf("%s\n", c); /* WRONG */
but this didn't work at all. The reason is that %s with printf expects a pointer-to-char, but you gave it a plain char. Suppose c contains the letter 'A'. This would end up asking printf to go to address 65 and begin printing characters until it finds the terminating '\0'. Why address 65? Because 65 is the ASCII code for A. But there's probably not a proper, null-terminated string starting at address 65 in memory; in fact there's a good chance your program doesn't have permission to read from address 65 at all.
So then you tried
printf("%s\n", &c); /* ALSO WRONG */
and this seemed to work. It "worked" because, if scanf succeeded in storing a complete string into c and the unallocated memory off to the right of it, and if clobbering that memory somehow didn't cause (too many) other problems, then when you pass the pointer &c to printf, printf can find those characters, making up a string, and print them out.
So it "works", but as I said, for the wrong reasons: in the process it stomps all over memory it doesn't "own", and sooner or later, something else is going to not work as a result.
How should you have scanned and printed a string? One way is like this, as we saw before:
char s[10];
scanf("%s", s);
printf("%s\n", s);
Now when scanf gets a pointer to the first element of the array s, it has 10 characters to play with.
We really do have to worry about the possibility that the user will type more than 9 characters. But there's a fix for that: we can tell scanf how long a string it's allowed to read, how many characters it's allowed to write to the array we handed it:
scanf("%9s", s);
That 9 in there tells scanf that it's not allowed to read more than 9 characters from the user. And since 9 is less than 10, there's still room for the terminating '\0' character.
There's much more that could be said about scanf. As chqrlie noted in a comment, it's important to check its return value, to make sure it succeeded in converting as many values as you wanted it to. It's got some strange rules about whitespace. Unless you know what you're doing, you can't intermix calls to scanf with calls to other input-reading functions like getchar or fgets -- you'll get strange results. And, finally, scanf is so persnickety and (in the end) so lacking in truly useful functionality that it's not really worth using at all. But those are topics for another day, since this answer is tl;dr already.
The %s format specifier requires a pointer to a string. When used with scanf, it must be a char array with enough characters for the word you enter plus the trailing null byte that indicates the end of the string. In printf() it has to be a null-terminated char array.
Using a pointer to a char variable doesn't work, because it doesn't have room for the null byte. You're causing undefined behavior by writing outside the variable.
char word[100];
scanf("%s", word);
printf("%s\n", word);
You can use %c to read and write a single character rather than a string of multiple characters.
char letter;
scanf("%c", &letter);
printf("%c\n", letter);
In statement char a; a is a character variable & to scan a char variable use %c format specifier.
scanf("%s",a);/* %s expects base address of char buffer, not single char */
scanf(" %c",&a);/* this is correct */
If you want to scan using %s then your input should be char buffer like char buf[10]. for e.g
char a[10];
scanf("%s",a);
u don't need to put &(ampersand) sign in printf when u use %c or %d ? no need to provide address & to printf() as printf() job is to print not to scan. for e.g
char input;
scanf("%c",&input);/* here you need &, As scanf() will store input char into
address you provided i.e &input */
printf("%c",input);/*here no need &input, bcz input char already stored,
printf will just print the char*/
Well, if you print the address you can use %p.
printf("%p",a);/*a is char buffer */

Format Specifiers in C and their Roles?

wrote this code to "find if the given character is a digit or not"
#include<stdio.h>
int main()
{
char ch;
printf("enter a character");
scanf("%c", &ch);
printf("%c", ch>='0'&&ch<='9');
return 0;
}
this got compiled, but after taking the input it didn't give any output.
However, on changing the %c in the second last line to %d format specifier it indeed worked. I'm a bit confused as in why %d worked but %c didn't though the variable is of character datatype.
Characters in C are really just numbers in a token table. The %c is mainly there to do the translation between the alphanumeric token table that humans like to read/write and the raw binary that the C program uses internally.
The expression ch>='0'&&ch<='9' evaluates to 1 or 0 which is a raw binary integer of type int (it would be type bool in C++). If you attempt to print that one with %c, you'll get the symbol table character with index 0 or 1, which isn't even a printable character (0-31 aren't printable). So you print a non-printable character... either you'll see nothing or you'll see some strange symbols.
Instead you need to use %d for printing an integer, then printf will do the correct conversion to the printable symbols '1' and '0'
As a side-note, make it a habit to always end your (sequence of) printf statements with \n since that "flushes the output buffer" = actually prints to the screen, on many systems. See Why does printf not flush after the call unless a newline is in the format string? for details
In a memory, int take 4 bytes of memory you are trying to storing the int values in a character which will return the ascii value not a int value in %c if you are using a %d which will return the int value which are storing in a memory of 4 bytes memory.

Int to char conversion while still using %c in the c language

I have the following code.
int ant = 10;
char converter = ant;
printf("This is where the char prints: %c", converter);
Why does the console only print out when this is run:
This is where the char prints:
Why does this happen? And is it possible to still use the %c and print out the value?
I understand that changing the %c to a %d will allow me to see the result but i wanna know why.
You are printing out the character encoded by the number 10: the format specifier %c is used to output the characters, rather than their numerical values.
In ASCII (most likely the encoding used), that's \n; the linefeed character. Your terminal is probably able to deal with that, and you'll see an extra line in your output.
If you want to print the numeric value of converter, then use simply %d as the format specifier (the char types are converted implicitly to int types at the calling site).

What is the correct specifier for char, double and float?

#include <stdio.h>
int main()
{
int i;
long int l;
long long int ll;
char a;
float F;
double D;
scanf("%i%li%lli%c%f%lf",&i,&l,&ll,&a,&F,&D);
printf("%i\n%li\n%lli\n%c\n%f\n%lf\n",i,l,ll,a,F,D);
return 0;
}
When I tried to print the value of a,F and D in the above program, it is printing 'h' for 'char' and 0.000000 and 0.000000 for float and double every time .
input: 3
444
12345678912345
a
334.23
14049.30493
output:3
444
12345678912345
0.000000
-0.000000
printf
There's no way to pass a char or a float to printf. They'll be promoted to int and double respectively in the processing of being passed.
When you pass a double, you can use %f or %lf (the latter was added in C99 though, so some older compilers don't support it).
If you want your int printed as a character, you can use the %c conversion. If you want it printed as a number, you can use the %d or %i conversion.
scanf
For scanf you don't want to pass any of the above--you want to pass a pointer to a (char | float | double).
As for the conversion to use, for a pointer to char you can use either %c or %s.
%s reads a "word"--it skips white-space characters, then reads a group of non-white-space characters.
%c does more like "raw" reading--for example, if you specify %15c it reads the next 15 characters, regardless of whether they're white-space or not.
With both %c and %s, you always want to pass a with (like %15s instead of just %s) to assure that the user can't enter too much data and overflow the buffer you've provide. scanf("%s", whatever); is pretty much equivalent to using gets.
With scanf, you pass %f to read a float and %lf to read a double.
Use %c for char .
Note - You should check return of scanf .
Demo
When you read your input, the character you read is the white-space between 12345678912345 and a. That means that the next format, the floating point, will try to read the letter a as a floating pointer value which will not work, and the scanf function will return without being able to correctly read and parse all input, leading to your output not matching the input. Many standard and system function returns a value saying if it succeeded or failed, the same with the scanf function, and if it doesn't fail completely it will return the number of successfully scanned and parsed items, which would be less than expected in your case.
The scanf reference in one of my comments will tell you that most formats skip leading white-space, but "%c" does not. If you want to skip leading space before attempting to parse a character, you need to tell scanf to do that, by inserting an actual space in the format string, like this:
scanf("%i%li%lli %c%f%lf",&i,&l,&ll,&a,&F,&D);
// ^
// Notice space here

How does scanf work in this simple program?

I have some trouble working with scanf in a while loop.
I wanted to make a program that would ask the user to write three integers and save them in an array of three positions. If the user writes something which is not an integer, the program should continue asking for an integer until (s)he enters it. But it didn't work properly.
So I tried to simplify the problem with this code:
#include <stdio.h>
int main()
{
int num1=1;
int num2=2;
int num3=3;
printf ("write a number\n");
scanf("%i", &(num1));
printf("%i\n",num1);
printf ("write a number2\n");
scanf("%i", &(num2));
printf("%i\n",num2);
printf ("write a number3\n");
scanf("%i", &(num3));
printf("%i\n",num3);
}
If the inputs are 3 integers, there's no problem. But if you write a character, for example a, for the first integer, the other 2 values are not scanned and it simply writes:
a
2
3
The last two values are the initialization values.
Can anyone tell me what I have to do?
The scanf function does not have to read after it encounters the first invalid character in the input.
The %i specifier allows a as a hexadecimal, but it MUST be preceded by 0x.
If a was the first character in the input, and it was supposed to match to %i, then scanf wouldn't have to read anything afterwards - it can stop at the first invalid character..
References:
http://www.gidnetwork.com/b-64.html
For each conversion specifier scanf tries to locate the appropriate data item. scanf reads the item, stopping when it encounters a character that can't possibly belongs to the item. If any item is not read successfully then scanf returns immediately without looking at the rest of the format string.
When you enter a 5 10, scanf finds a for the specifier %i. It immediately returns and stops reading other inputs 5 and 10.

Resources