Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
As a part of an assignment I've got, I need to get from a user a digit only using the <stdio.h> library.
do {
scanf("%d",&num);
} while (num>9 || num<0);
But the program will get from the user also chars and other things.
Any advice?
One way of solving this is getting the ASCII value of the scanned "digit" and making sure it lies between ASCII values 0X30 and 0X39 (or 48 and 57).
Seeing your logic, you seem to be interested in numbers greater than 9 (multiple digit numbers) and numbers less than 0 (signed numbers/integers).
I suggest instead of using scanf better use something like getchar which will return one character at a time.
A simple way to scan multiple digit numbers using getchar can be:
int getNumber()
{
int sign = 1;
int i = 0;
int ch;
ch = getchar();
if((ch == '-') || (ch == '+')) //check sign
{
if(ch == '-') sign = -1;
}
else
{
if (ch > '9' || ch < '0')
return NULL; // Your requirement - it's a non number
i *= 10;
i += ch - '0';
}
while ((ch = getchar()) != '\n') //get remaining chars
{
if (ch > '9' || ch < '0')
return NULL; // Your requirement - it's a non number
i *= 10;
i += ch - '0';
}
i *= sign; //change sign
return i;
}
You can call this function in place of scanf.
You can use getchar() to read a single character from stdin and then compare it to the ASCII values for 0 and 9 (your upper and lower bounds for a single character). The digit as an integer is equal to the character code minus the character code for 0.
#include <stdio.h>
int main(void) {
char c;
while((c = getchar()) >= '0' && c <= '9')
printf("Digit is: %d\n", c - '0');
return 0;
}
Related
This question already has answers here:
Numeric value of digit characters in C
(5 answers)
Closed 1 year ago.
while((c = getchar()) != EOF) {
if((c >= '0') && (c <= '9')) {
ndigits[length] = c;
length = length + 1;
}
}
I want to store each digit, in the array. But when I enter 123 and print the array, I get 50 51 52. How can I fix this issue?
Characters are numbers too. In this case, you have ASCII codes, or at least the ASCII subset of UTF-8 encoded Unicode code points. The integer '1' is indeed 49, '2' is 50, etc. When you store them in your array, it stores the numerical value of the ASCII code for that number. If you want the number itself, you can do something like:
if((c >= '0') && (c <= '9'))
{
ndigits[length] = c - '0';
length = length + 1;
}
I have a txt file that looks like the following:
1:0
2:0
3:1
4:0
...
99:1
100:1
I would like to store the 1s and 0s inside an array (slot[]), (regardless of what's on the left side of the ':'s), but I can't figure out how. Here's a snippet of my code for that:
while((ch=fgetc(fptr)) != EOF)
{
if(ch == ':')
{
slot[j] = fgetc(fptr); //saves the character right after ":"into slot[j]?
j++;
}
}
I know it's more complicated than this because it doesn't work. I've searched for a long time but can't find it, maybe because I didn't search for the correct terms.
How can I fix this?
Thanks in advance.
It seems pretty straight forward with some minor changes, since your specs state that there is always 1 digit on the right and is always 0 or 1, something like this should do it:
if (fptr != NULL)
{
int ch;
int j = 0;
while ((ch = fgetc(fptr)) != EOF)
{
if (ch == ':')
{
if ((ch = fgetc(fptr)) != EOF) // get digit after :
{
slot[j++] = ch - '0'; // for int array *
//slot[j++] = ch; // for char array
}
else
{
break;
}
}
}
}
Or, for a more robust method using fgets:
if (fptr != NULL)
{
char temp[100]; // must be large enough to hold the line
char *ch;
int j = 0;
while (fgets(temp, sizeof temp, fptr)) // read whole line
{
ch = strchr(temp, ':'); // find :
if (ch != NULL && (ch[1] == '1' || ch[1] == '0'))
{
// add next digit to slot[] if it's 1 or 0
slot[j++] = ch[1] - '0'; // or remove - '0' for char slot[]
}
}
}
Requires string.h header for strchr.
* Check this post if you want to know more about character to digit conversion:
Why is there a need to add a '0' to indexes in order to access array values?
The reason it doesn't do what you expect is because you are reading characters and expecting them to be numbers. A character in C has an integer value. The mapping is called ASCII (have an internet search for "ASCII table"). The uppercase alphabet starts at 65, the lower case alphabet starts at 97, and the numeric digits start at 48. So, if '0' is 48 and '1' is 49 you can change '0' and '1' to 0 and 1 respectively by subtracting 48 from each:
slot[j] = fgetc(fptr) - 48;
And that works but later you will forget what 48 means and have to look at an ASCII table again so you should use characters:
slot[j] = fgetc(fptr) - '0';
Which does the same exact thing but makes it obvious why you are subtracting a value.
You can use the same trick to convert upper case to lower case:
if (ch >= 'A' && ch <= 'Z') ch += 32;
Or lower case to upper case:
if (ch >= 'a' && ch <= 'z') ch -= 32;
But of course, there are library functions called tolower() and toupper() which are much more expressive which is why nobody does it that way.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I found this Caesar cipher encryption code on the web and I'm trying to understand how it works
#include<stdio.h>
int main()
{
char message[100], ch;
int i, key;
printf("Enter a message to encrypt: ");
gets(message);
printf("Enter key: ");
scanf("%d", &key);
for(i = 0; message[i] != '\0'; ++i){
ch = message[i];
if(ch >= 'a' && ch <= 'z'){
ch = ch + key;
if(ch > 'z'){
ch = ch - 'z' + 'a' - 1;
}
message[i] = ch;
}
else if(ch >= 'A' && ch <= 'Z'){
ch = ch + key;
if(ch > 'Z'){
ch = ch - 'Z' + 'A' - 1;
}
message[i] = ch;
}
}
printf("Encrypted message: %s", message);
return 0;
}
Meaning of if(ch >= 'a' && ch <= 'z')
Like does c include the alphabet as an array or something or how does it know that the letter is b or others ?
Adding an int to a char in ch = ch + key;
this math thing ch = ch - 'Z' + 'A' - 1;
And thanks very very much
The codes adds a certain value (key) to each inputed character and "rotates" the character in the range a-z if small caps and A-Z if big caps.
In C each single character has an implicit ascii/int value and the compare operator is used to decide if the inputted character is in the set of characters a-z (which are aligned after each other) or if it is in the set of A-Z which also follow behind each other.
The rest of the code deals with the wraparound if the inputted character plus the key "overshoots" f.e. z or Z and loops it around by substracting the value of 'z' and adding the value of 'a' -1 so that the resulting char is again one in the selected range of a-z or A-Z
This question already has answers here:
Use of s[i] - '0' [duplicate]
(3 answers)
Closed 5 years ago.
Hey I can't understand why my code doesn't write when I put just ++ndigit[c] (instead of ++ndigit[c -'0'], then with ++nchar[c] it's ok.
If you have any tuto I'll be really interested !
#include <stdio.h>
int main()
{
int c, i, y, ns;
int ndigit[10];
int nchar[26];
ns = 0;
for(i = 0; i >= 0 && i<= 9; ++i) {
ndigit[i] = 0;
}
for(y = 'a'; y <= 'z'; ++y) {
nchar[y] = 0;
}
while((c = getchar()) != EOF) {
if(c == ' ' || c == '\t') {
++ns;
}
if(c >= 'a' && c <= 'z') {
++nchar[c];
}
if(c >= '0' && c <= '9') {
++ndigit[c];
//++ndigit[c-'0'];
}
if(c == '\n') {
printf("chiffres: ");
for(i=0;i<10;++i) {
printf("%d:%d ", i, ndigit[i]);
}
printf("lettres: ");
for(y='a';y<='z';++y) {
printf("%d:%d ", y, nchar[y]);
}
printf("space: %d\n", ns);
}
}
}
Actually when you set the variable to c='0', it means that the value of c is now the ascii value of '0' and that is = 48.
Since you are setting the value of c to 48 but the array size is 10, your code will get a runtime exception because you are trying to access an index that doesn't even exist.
Remember when you use '0' it means character. So setting this value to an int variable makes the value equals to the ascii value of that character. Instead you can use c=0 directly.
Because the character '4' (for example) is usually not equal to the integer 4. I.e. '4' != 4.
Using the most common character encoding scheme ASCII, the character '4' has the value 52, and the character '0' has the value 48. That means if you do e.g. '4' - '0' you in practice to 52 - 48 and get the result 4 as an integer.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am trying to create my personal atoi function but i doesn't work properly. I don't know why.
void ft_putchar(char c)
{
write(1, &c, 1);
}
int ft_atoi(const char *str)
{
int i;
i = 0;
while (str[i] == 9 || str[i] == 32 || str[i] == 43 || str[i] == 45)
i++;
while (str[i] > 48 && str[i] < 57)
{
ft_putchar(str[i]);
i++;
}
return (0);
}
int main(void)
{
printf("%d", atoi(" 2794ffafsaasf"));
printf("\n%d",ft_atoi(" 2794fsffsf"));
return(0);
}
I kinda works but it doesn't. It gives me a weird result where it even ignores '\n'.
The result it gives me is this.
272794 and a new line.
with only my function it gives me only the number 27.
EDIT:
I have created a new program. But it still doesn't work. It simply can't see digits.
int ft_atoi(const char *str)
{
int i;
int n;
i = 0;
while (str[i] == '\t' || str[i] == ' ' || str[i] == '+' || str[i] == '-')
++i;
n = i;
while (str[n] >= '0' && str[n] <= '9')
{
++n;
}
return(str[n]);
}
Your test for digits has the bounds set wrong. You're testing str[i] > 48 && str[i] < 57, but 48 is the ordinal for the 0 character, and 57 is the ordinal for 9. This means you only consider 1 through 8 inclusive to be numeric digits, and you stop parsing 2794fsffsf at the 9, not at the first f.
Changing the test to str[i] >= 48 && str[i] <= 57 would fix the bounds issue, but would still be less than self-documenting. To make it obvious what you're doing to people who don't have the ASCII tables memorized, you could do:
while ('0' <= str[i] && str[i] <= '9')
or possibly slightly slower but even more obviously with ctype.h:
while (isdigit(str[i]))
You could similarly replace the many non-obvious tests for whitespace ordinal values with isspace(str[i]).
First thing is to ignore leading whitespace. You can do that with i as you're doing, but it's easier to do it by shifting the start of the string forward. I'm guessing that you're reimplementing the standard C library as an exercise. I'm not, so I'm going to make use of the ctype.h functions. Adjust as you like, the basic code remains the same. You should probably write your own ft_isspace and ft_isdigit rather than hard coding the logic.
/* Move str to point at the first non-space character */
while( isspace(str[0]) ) {
str++;
}
Now there's no need for an i to hold your place, you can just work with str[0] and it will be the first non-whitespace character.
Next we need to find and add up our digits. Again, I'll use isdigit. Follow the advice in ShadowRanger's answer if you can't use that function.
The technique is to convert each character to a digit and add it to the total. Since we're reading a number left to right, each new digit multiplies the existing sum by 10. For example, if we had 1234 it would be... 1 then 10 + 2 then 120 + 3 then 1230 + 4.
int num = 0;
while( isdigit(str[0]) ) {
int digit = str[0] - '0';
num *= 10;
num += digit;
str++;
}
Once again I'm manipulating the pointer rather than using an index. This is just to save an integer, and to avoid mixing up two string iteration techniques in a single function.
And, finally, don't forget to return the number!
return num;
What about negative numbers? We need to look for a - before we check for digits, if it's there flip the sign. We also need to handle a + and ignore it.
/* Assume it's positive. */
short sign = 1;
/* Check for a sign. */
switch( str[0] ) {
case '-':
sign = -1;
str++;
break;
case '+':
str++;
break;
}
And then multiply by the sign to flip the result.
return sign * num;
Your code only writes out the numbers - and not all, as pointed out before me (because it excludes '0' and '9' and they should be included!) - to the file identified by 1 (what is maybe the standard output, I don't remember exactly...), and returns 0 as the parameter of the printf. It seems to me a little strange, you only had 27 printed out with your function, but it might be environment(?) specific. (I have not tested it, so it possibly not exactly work as I suppose...)
I've made my version of atoi, hoping I can show where to start / the way how you should do yours:
int nvi9_atoi(const char *s) {
int n = 0, valid = 0, prev = 0;
while(1) { // infinite loop
if (*s == '\0') break; // if it is the end of the string, finish further processing
if (*s >= '0' && *s <= '9') { // check whether the current character is an ascii number
n *= 10; // "move" all previous digits (eg. 1 -> 10, 43 -> 430); if n is 0, this has no effect
if (n >= 0) n += (*s - '0'); // if n is not negative, add the value of the last digit (here is ascii-number "conversion"!)
else n -= (*s - '0'); // if it is negative, the number should be substracted (note eg. if there was -10 so far, and the new number is 2, the new value should be -12, not -8)
if (n > 0 && !valid) { // if n not 0, and there was no digits before it, check if there was a minus sign before
valid = 1; // preventing more check
if (prev == '-') n *= -1; // makes n negative
}
} else if (valid) break; // if there was numbers processed, but the current character is not a number, finish loop
prev = *s; // store current character for minus sign checking of next loop
s++; // move string pointer to the next character
}
return n; // return the converted value
}
It is also untested, so fixes / corrections / improvements are welcome!
This function can even process strings like " sfg afg-65sd1g". In that case the returned value will be -65, because it looks for the first number, then returns.