Get whole number from input using only getchar() and convert to int - c

For a school assignment i have to make a C program that reads a whole number, that may be preceded by a '+' or '-'. i can only use getchar().
I can convert a single char to an int using int i = ch - '0' but I want to read in multiple chars. besides that I need to check if the input is correct (eq. no not-numerical charachters)
I have this so far:
int main(void) {
int i;
char ch;
printf("voer een getal in: ");
while ((ch = getchar()) != '\n') {
i = ch - '0';
}
printf("het ingevoerde getal is: %d\n", i);
return EXIT_SUCCES;
}
Edit: I get that this isn't really the place for problems like this (I should learn to fix it myself, not get others to fix it for me) but I didn't know what to do anymore. thanks you for guiding me to the right path

This should get you started:
int main(void) {
int i = 0;
int ch;
printf("voer een getal in: ");
while ((ch = getchar()) != '\n') {
if (ch > '9' || ch < '0')
continue; // or print an error and exit
i *= 10;
i += ch - '0';
}
printf("het ingevoerde getal is: %d\n", i);
return EXIT_SUCCES;
}
I'll leave detecting the potential + / - sign as an exercise.

If your school allows you to use shift operators then here is a quick way to get integer from the user and as per their requirements you can show the + or - sign preceding the integer. But remember not to just copy paste it. Understand the code first.
int main(){
int i = 0;
char c;
char sign = 43;
printf("voer een getal in:\n");
c = getchar();
if(c == 45)
sign = 45;
for(; (c<48 || c>57); c = getchar());
for(; c>47 && c<58 ; c = getchar()){
i = (i<<1) + (i<<3) + c - 48;
}
printf("het ingevoerde getal is: %c%d\n",sign, i);
return 0;
}

Reading in multiple characters, and determine whether positive, negative, and value:
int sign = 1;
ch = getchar(); //look at first char (might be a sign indicator)
if((ch == '-') || (ch == '+')) //consume first char if either `-` or `+`
{
if(ch == '-') sign = -1;
}
else //first char non-sign - handle as digit
{
if (ch > '9' || ch < '0')
continue; // or print an error and exit
i *= 10;
i += ch - '0';
}
while ((ch = getchar()) != '\n') //get remaining chars (assume no embedded sign chars)
{
if (ch > '9' || ch < '0')
continue; // or print an error and exit
i *= 10;
i += ch - '0';
}
i *= sign; //apply sign to value

I think this will work.
while ((ch = getchar()) != '\n') {
i = ch - '0' + i * 10;
The problem in your code is that you are overwriting i every time you read a new character. You need to store the digit you read, and then add to it.

You should take care about not number characters :
while((ch=getchar()) != '\n')
if(ch >= '0' && ch <= '9')
i += 10* i + (ch - '0');
For the '-' or '+' at the begining you could store the first getchar(). A solution could be :
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int i = 0;
char ch,first_ch;
printf("voer een getal in: ");
ch = first_ch = getchar();
while (ch != '\n') {
if(ch >= '0' && ch <= '9')
i = 10* i + (ch - '0');
ch = getchar();
}
if(first_ch == '-')
i *= -1;
printf("het ingevoerde getal is: %d\n", i);
return EXIT_SUCCESS;
}

Related

Hexadecimal input function calculates wrong values

I'm writing a function that can read integers expressed in hexadecimal.
This is my code. The main function should not be modified.
#include <stdio.h>
#include <ctype.h>
#define SIZE 100
main()
{
int array[SIZE], n;
int gethex(int*);
int i, sum;
for (n = 0; n < SIZE && gethex(&array[n]) != EOF; n++)
;
sum = 0;
for (i = 0; i < n; i++)
sum += array[i];
printf("The sum is %d\n", sum);
}
int gethex(int *pn)
{
int c, sign;
c = getchar();
while (isspace(c))
;
if (!isxdigit(c) && c != EOF && c != '+' && c != '-') {
ungetc(c, stdin);
return 0;
}
sign = (c == '-') ? -1 : 1;
if (c == '+' || c == '-')
c = getchar();
for (*pn = 0; isxdigit (c); c = getchar()) {
if (c >= '0' && c <= '9') {
*pn = 16 * *pn + (c - '0');
}
else if (c >= 'a' && c <= 'f') {
*pn = 16 * *pn + (c - 'a' + 10);
}
else if (c >= 'A' && c <= 'F') {
*pn = 16 * *pn + (c - 'A' + 10);
}
}
*pn *= sign;
if (c == EOF) {
*pn = c;
return c;
}
}
The result value should come out like this.
-FFec
10000
^Z
The sum is 20
However, my code outputs
The sum is 1717986860
What's wrong?
At least these problems:
Warnings not fully enabled
Warnings are not fully enabled, losing OP and others valuable time. #Jens
End of gethex() lacks a return value.
warning: control reaches end of non-void function [-Wreturn-type]
Infinite loop
Once a '\n is read, loop never ends. #Weather Vane
while (isspace(c))
;
Non hex input also set up an infinite loop with ungetc(c, stdin); as that same c will repeatedly get read on the next function call.
if (!isxdigit(c) && c != EOF && c != '+' && c != '-') {
ungetc(c, stdin);
return 0;
}
int overflow possible
Code like *pn = 16 * *pn + (c - '0'); and *pn *= sign; can lead to int overflow, which is undefined behavior (UB). Robust code would prevent that.
Some untested code to fix these issues.
// Return 0 if non-numeric input detected.
// Return 2 when input out of int range
// Return 1 on success
// Return EOF when input is only white-space, sign or none
int gethex(int *pn) {
int ch;
// Consume leading white-space
do {
ch = getchar();
} while (isspace(ch));
// Get sign, if any
int sign = ch; // remember 1st
if (ch == '-' || ch != '+') {
ch = getchar();
}
if (ch == EOF) {
return EOF;
}
if (!isxdigit(ch)) {
// Consume non-numeric input
return 0;
// Perhaps better to return EOF here to stop calling code.
}
int overflow = 0;
int sum = 0;
while (isxdigit(ch)) {
int digit = 0;
if (isdigit(ch)) {
digit = ch - '0';
} else if (isupper(ch)) {
digit = ch - 'A' + 10;
} else if (islower(ch)) {
digit = ch - 'a' + 10;
}
if (sum <= INT_MIN / 16
&& (sum < INT_MIN / 16 || digit > -(INT_MIN % 16))) {
overflow = 1;
sum = INT_MIN;
} else {
// Accumulate as a negative number as there are more
// negative vales than positive ones.
// This prevents bad code like -INT_MIN later.
sum = sum * 16 - digit;
}
}
if (sign != '-') {
if (sum < -INT_MAX) {
overflow = 1;
sum = INT_MAX;
} else {
sum = -sum;
}
}
*pn = sum;
ungetc(ch, stdin);
return overflow ? 2 : 1;
}

why the program omitted some lines? (c program to encrypt text)

i am trying to make a program that encrypt text with a Caesar cipher.The number of positions to shift will be given to the program as a command line argument and characters other than letters should not be encrypted. The program should stop only at the end of input. My issue is that the program omit the lines that mod the number. the program is run on a platform that provided by my school, i am not sure what it is. please kindly help me to fix the program.
here is my program
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main( int argc, char *argv[] ) {
int num = atoi(argv[1]);
char caesar[100];
char ch;
int shift = num%26;
while ( fgets(caesar, 100, stdin) != NULL){
for(int i = 0; i < strlen(caesar); i++){
ch = caesar[i];
if( ch >= 97 && ch <= 122){
if( ch + shift < 97){
ch = ch + shift + 26;
}
else if( ch + shift > 122){
ch = ch + shift - 26;
}
else{
ch = ch + shift;
}
caesar[i] = ch;
}
else if( ch >= 65 && ch <= 90){
if( ch + shift < 65){
ch = ch + shift + 26;
}
else if( ch + shift > 90){
ch = ch + shift - 26;
}
else{
ch = ch +shift;
}
caesar[i] = ch;
}
}
}
printf("%s", caesar);
return 0;
}
here is some examples which have correct output
here is what my program did. the program ignored shift = num%26 and i can't figure out why

I can't figure out how to use the strlen in my C code

I just started learning C. I am supposed to create a password program where the user inputs strings that are at least 8 characters longs. It also needs to have one upper case, one lower case, one digits, and one symbol from this set {#, %, +}. I can't try to figure out the loop where it prints invalid when the user doesn't type in at least 8 characters. I tried using strlen but it gives me an error passing argument 1 of ‘strlen’ makes pointer from integer without a cast can someone help me?
#include <stdio.h>
#include <string.h>
int main()
{
int n;
int k;
char ch;
unsigned char uFlag = 0, cFlag = 0, dFlag = 0, hFlag = 0, aFlag = 0;
printf("Enter a password: ");
ch = getchar();
n = strlen(ch);
k = n - 1;
while (ch != '\n')
{
if(ch >= 'A' && ch <= 'Z')
uFlag = 1;
else if(ch >= 'a' && ch <= 'z')
cFlag = 1;
else if(ch >= '0' && ch <= '9')
dFlag = 1;
else if(ch == '#' || ch == '%' || ch == '+')
hFlag = 1;
else if (k >= 8)
aFlag = 1;
ch = getchar();
}
if (uFlag == 1 && cFlag == 1 && dFlag == 1 && hFlag == 1 && aFlag == 1)
{
printf("Password entered is valid.\n");
}
else
{
printf("Password entered is invalid.\n");
}
return 0;
}
char ch; defines a variable for a single character, not for a string. So you cannot use strlen(ch), because strlen expects a pointer to a string (and not a single character).
As you are reading in one character after another with ch = getchar() in a loop, you actually do not compose any string. The only thing you need to do is increment k with each iteration:
k = 0;
while (ch != '\n')
k++;
...
ch = getchar();
}
You must be used an array of characters and not an char. In your code, you have written -
n = strlen(ch);
However, strlen() accepts char* or an array of character or pointer to a string as parameter. You are passing ch which is of type char and is the wrong parameter data type. This is main reason why you are getting the error.
I have made minor edits in your program which you can refer below -
#include <stdio.h>
#include <string.h>
int main()
{
int i=0; //i to maintain current index in char array-ch
char ch[100],c; //or you could use dynamic allocation by asking user for input, c will read user input
unsigned char uFlag = 0, cFlag = 0, dFlag = 0, hFlag = 0, aFlag = 0;
printf("Enter a password: ");
c = getchar(); //read the input into character as you did
ch[i]=c; //assign the character to current index in ch array
while (ch[i] != '\n') //check until user hits enter
{
if(ch[i] >= 'A' && ch[i] <= 'Z')
uFlag = 1;
else if(ch[i] >= 'a' && ch[i] <= 'z')
cFlag = 1;
else if(ch[i] >= '0' && ch[i] <= '9')
dFlag = 1;
else if(ch[i] == '#' || ch[i] == '%' || ch[i] == '+')
hFlag = 1;
//the below should be if and not if else as in your posted code for it to work as expected
if (i >= 8) // sets the flag once length of array get over 8
aFlag = 1;
i++; // first increment index since we have already read at current index
c = getchar(); //same as before
ch[i] = c;
}
if (uFlag == 1 && cFlag == 1 && dFlag == 1 && hFlag == 1 && aFlag == 1)
{
printf("Password entered is valid.\n");
}
else
{
printf("Password entered is invalid.\n");
}
return 0;
}
Hope this solves your problem !
regarding:
ch = getchar();
n = strlen(ch);
the function getchar() only inputs a single char, not a string.
the function strlen() expects a NUL terminated array of characters.
Suggest inputting the password using;
fgets( buffer, sizeof( buffer ), stdin );
rather than using many calls to getchar()
then use:
buffer[ strcspn( buffer, "\n" ) ] = '\0';
to remove an newline character
then looping through the buffer[], checking each character
for( size_t i=0; buffer[i]; i++ )
{
// perform all the needed checks of the password
}

Circular shift cipher

I have written a circular shift cipher for key -1 billion to +1 billion for encrypting messages of maximum 200 characters including 0 to 9, a to z and A to Z.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char input[215], key[11], msg[201], output[201], ch;
int i, j, k, shiftkeychar, shiftkeynum;
printf("Input: ");
gets(input);
for (i = 0; input[i] != ':'; i++)
key[i] = input[i];
key[i] = '\0';
i++;
k = 0;
for (j = i; input[j] != '\0'; j++) {
msg[k] = input[j];
k++;
}
msg[k] = '\0';
printf("\nmessage: %s\n", msg);
printf("key: %s\n", key);
shiftkeychar = atoi(key) % 26;
shiftkeynum = atoi(key) % 10;
printf("shiftkey for characters: %d\n", shiftkeychar);
printf("shiftkey for numbers: %d\n", shiftkeynum);
strcpy(output, msg);
for (i = 0; output[i] != '\0'; i++) {
ch = output[i];
if (ch >= 'A' && ch <= 'Z') {
ch = ch + shiftkeychar;
if (ch > 'Z') {
ch = ch - 'Z' + 'A' - 1;
}
else if (ch < 'A') {
ch = ch + 'Z' - 'A' + 1;
}
}
else if (ch >= 'a' && ch <= 'z') {
ch = ch + shiftkeychar;
if (ch > 'z') {
ch = ch - 'z' + 'a' - 1;
}
else if (ch < 'a') {
ch = ch + 'z' - 'a' + 1;
}
}
else if (ch >= '0' && ch <= '9') {
ch = ch + shiftkeynum;
if (ch > '9') {
ch = ch - '9' + '0' - 1;
}
else if (ch < '0') {
ch = ch + '9' - '0' + 1;
}
}
output[i] = ch;
//printf("output[%d]: %c", i, ch);
}
printf("Output: %s", output);
return 0;
}
This Circular shift cipher is working well for Capital letters and digits. However for small letters e.g. if message is 'xyz' and key is more than 5 (i.e., 6,7,...25) its generating some arbitrary output. input format is: "key:message". output is:"encrypted message".
Your character ch is a char, which in C may or may not be signed. On your machine, it seems to be signed, which means that you can store values from −128 to 127. The lower-case letters occupy the ASCII codes from 97 to 122. When you say:
ch = ch + shiftkeychar;
you may overflow the signed char for letters at the back of the alphabet. Technically, this is undefined behaviour; in practice you will probably get negative values, which will lead to strange characters later on.
To resolve your problem, make ch an int.

C hex to dec conversion, I don't understand what's wrong with my code

My code should find hex numbers in a user input (followed or not by 0x), copy them in an array as a string and, every time it finds a non 1-9 a-f A-F character or EOF, it should execute the htoi function converting the characters in the string into a decimal number, proceeding from right to left and using a multiplier to account for the position. It doesn't do what it's supposed to do. It generates numbers that have nothing to do with the decimal equivalent of my hex numbers.
#include <stdio.h>
#include <string.h>
#include <math.h>
int htoi(char num[]);
int main()
{
int c,i = 0;
char num[1000];
while ((c = getchar()) != EOF)
{
if ((c > '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'a' && c <= 'f'))
{
num[i] = c;
i++;
}
else if (c == '0')
{
if ((c = getchar) == 'x' || c == 'X')
{
num[i] = '\0';
printf("%d", htoi(num));
i=0;
}
else
{
num[i] = c;
i++;
}
}
else
{
num[i] = '\0';
if (num[0] != '\0')
{
printf("%d", htoi(num));
}
i=0;
}
}
num[i] = '\0';
if (num[0] != '\0')
{
printf("%d", htoi(num));
}
i=0;
return 0;
}
int htoi(char num[])
{
int c,i, dig;
int dec;
int multiplier = 1;
for (i = strlen(num)-1; i >= 0; i--)
{
c = num[i];
if (c > '0' && c <= '9')
{
dig = c - '0';
}
else if (c > 'a' && c <= 'f')
{
dig = c - 'a' + 10;
}
else if (c > 'A' && c <= 'F')
{
dig = c - 'A' + 10;
}
dec = dec + dig * multiplier;
multiplier * 16;
return dec;
}
}
Three problems:
multiplier * 16; just throws away the result. You'd want multiplier *= 16
return dec returns immediately with the current value of dec. You should have that after the loop.
The variable dec is uninitialized, which means it will have an indeterminate value. Using it without initialization, like you do, will lead to undefined behavior.
There are other problems as well, some of which would have been caught by the compiler leading to errors or warnings. The three above was just what I found after a quick glance.

Resources