Check that an array contains only numbers - c

I'm having a problem where I am wanting to go through an array and check that only positive numbers have been entered. I know that it is possible to use isDigit from ctype.h but I'd rather construct something myself. The way I think it is possible, is to iterate through each element of the array and see if the value stored there is between 0 and 9, but it isn't working. This is my code so far:
char testArray[11] = {'0'};
printf("Enter a string no longer than 10 chars");
scanf("%s", testArray);
int x;
int notanumber = 0;
for (x = 0; x < 11; x++) {
if ((testArray[x] < 0) || (testArray[x] > 9)) {
notanumber++;
}
}
printf("%i", notanumber);

It is not working because 0 and 9 are integers not characters.
Change your if condition to
if((testArray[x] >= '0') || (testArray[x] <= '9')){ ... }
to check the digits from 0 to 9.

this line
if((testArray[x] < 0) || (testArray[x] > 9)){
should be replaced by
if((testArray[x] < '0') || (testArray[x] > '9')){

Related

Issues with a Caesar Cipher

So the main issue is that the addition of (-5 to 4) to the characters in the entered string is all messed up to show possible words that were encrypted. When the loop runs the enter characters are not the starting point thus throwing everything else off. Additionally, I cannot get the repeat = false statement to register.
#include<stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
int main()
{
char encrypted_string[100];
char z;
char stop[]="STOP";
int x=-5, y, len;
bool repeat = true;
while (repeat)
{
printf("Enter the encrypted word (type STOP to quit) : ");
fgets(encrypted_string, 100, stdin);
if (strcmp(encrypted_string, stop)== 0)
{
repeat = false;
}
//len=strlen(encrypted_string);
while (x < 5)
{
for (y = 0; encrypted_string[y] != '\0'; y++)
{
z = encrypted_string[y];
if (z >= 97 && z <= 122)
{
z=z+x;
if (z < 97)
{
z=z+(122-97)+1;
}
encrypted_string[y] = z;
}
else if (z >= 65 && z <= 90)
{
z=z+x;
if (z < 65)
{
z=z+(90-65)+1;
}
encrypted_string[y] = z;
}
}
printf("For shift of %d, decrypted word is %s\n", x++, encrypted_string);
}
}
return 0;
}
char stop[]="STOP";
fgets(encrypted_string, 100, stdin);
if (strcmp(encrypted_string, stop)== 0)
fgets() leaves the trailing newline in the buffer, so this will never be true if the user hit enter at the end of the line.
if (z >= 97 && z <= 122)
These look a bit like magic numbers, probably better to write 'a' and 'z' instead.
if (z >= 97 && z <= 122) {
z=z+x;
if (z < 97)
What if the increment x is positive? z could go over 122.
Actually, why is it named x? It's the shift offset, so call it that.
Similarly, y is an index, so perhaps i instead. Especially confusing is that you have x, y and z that are three totally different things.
while (x < 5) {
for (y = 0; encrypted_string[y] != '\0'; y++) {
...
encrypted_string[y] = z;
You're modifying the same string you read again on the next iteration. For the input foo, it does a shift of -5 giving ajj, then a shift of -4 from that, giving wff, etc.

decompress string in c

I have a string like this :
h12pw3Bb4
I want decompressed to :
hhhhhhhhhhhhpwwwBbbbb
for numbers less than 10 i wrote this code but it isn't work for numbers greater than 10
for(int j = 0;j< strlen(txt);j++){
if(isdigit(txt[j])){
int x = txt[j];
x = x - 49;
while(x > 0){
printf("%c" , txt[j-1]);
x--;
}
}else{
printf("%c" , txt[j]);
}
}
See h12 implies print 'h' 12 times right. But you are reading character by character then when '1' is read 1 h will be print and next when 2 is read 2 h's are printed. So based on your code you are not going to achieve what you desire. You need to change it.
So, I think this should help:
int st = 0;
for(int j = 0;j< strlen(txt);) {
int x = 0;
while(j < strlen(txt) && isdigit(txt[j])) {
x = (x * 10) + (txt[j] - '0');
j++;
}
x--;
while(x > 0){
printf("%c" , txt[st]);
x--;
}
if (j < strlen(txt))
printf("%c" , txt[j]);
st = j;
j++;
}
Assumptions :
The first number must be a letter.
Please change them accordingly to your requirements.
Right, with multi-digit numbers you need several iterations of the loop before knowing the value of x.
So personally what I would do is this:
define and initialize two variables int x and char c outside of the loop
in the if block: calculate the value of x (multiplying it by 10 and adding txt[j] - 49 ?)
in the else block: print c x times, reset x to 0, set c to txt[j]

atoi function doesn't work in for loop

I am trying to get the output of this equation :
44 - 10 + 11 / 5
it work properly as follow :
char str[] = "44 - 10 + 11 / 5";
int sum = 0 ;
sum += atoi(str); // 0 + 44
sum += atoi(str+3); // 44 + 10
sum += atoi(str+5); // 54 + 11
sum += atoi(str+7); // 65 / 5 = 13
printf("%d/n",sum); // output = 13
but it doesn't work if I put the atoi() function in the for loop:
char str[] = "44 - 10 + 11 / 5";
int sum = 0;
int i;
sum += atoi(str);
for (i = 0; i < 100; i++) {
if (!(str[i] >= 0 && str[i] <= 9)) { //if str[i] is not a number
sum += atoi(str + i);
}
}
printf("%d/n", sum); // output = 0
You are comparing a char value that contains the ASCII representation of a number, to an actual number. Change
if(!(str[i]>=0 && str[i]<=9)){
to
if(!(str[i]>='0' && str[i]<='9')){
I did not check if the rest of the code is correct, but certainly, this is one issue.
if(!(str[i]>=0 && str[i]<=9)){ //if str[i] is not a number
This is incorrect. '0' and 0 are not same. Neither is 9 and '9'. The value of '9' will be integer that represents '9' in ASCII chart.
Rest of the logic seems suspicious too, for example what happens if you have "55", code will enter if twice, once for 55 and second time for 5, isn't it?
Because your code does not do the same calculations as your previous one. In the first one you are shifting the pointer to the next number and you are adding it to the number, so your code does the following 44 + 10 + 11 + 5.
In the second case you are checking whether the character code is between 0 and 9, but the numbers are between 48 and 57 - the characters '0' and '9'. So the if statement would be always wrong. Your intention was probably this, but it won't work.
for(i = 0; i < 100 ; i++){
if(!(str[i]>='0' && str[i]<='9')){ //if str[i] is not a number
sum += atoi(str+i);
}
}
This also does not work, because here you are doing the wrong shifts of the pointer by one, resulting in the reading of the following numbers: 44, 4, 10, 0, 11, 1, 5. Because of the atoi properties. To perform the exact same code you did before you`d have to write the following code:
int skip_non_diggits(int i, char *str) {
while (str[i] < '0' || str[i] > '9') {
if (str[i] == 0)
return -1; //end of string case
i++;
}
return i;
}
int skip_diggits(int i, char *str) {
while (str[i] >= '0' && str[i] <= '9') {
if (str[i] == 0)
return -1; //end of string case
i++;
}
return i;
}
These functions could be used as follows:
int i = 0, sum = 0;
while (i != -1) {
sum += atoi(str+i);
i = skip_diggits(i, str); // positions i after the current number
i = skip_non_diggits(i, str); // positions i at the begin of the next number
}
BTW
Don't use for (i = 0; i < 100; i++) to iterate through the strings you don't know the size of. If the string is shorter in length than 100 you're derefferencing memory which probably isn't yours creating undefined behavior. Instead check the strlen method or check whether the character is not equal to \0 which in C indicates the end of the string.
This seems a bit odd. What's the goal?
Agree with previous comment.
Why are you doing atoi() on what is NOT a number?
You will go past the end of the string.
Your spaces COUNT in the example
and so on.
you don't update i when you find a number, so you will count "44" as 44 first and 4 second.
If you're trying to learn, hook up a debugger, step through the code, and see how the data changes.

'if' statement in C not executing even though conditions are met

I'm a first time programmer trying to complete a simple command line program as part of the first assignment for an online course I am taking, but I seem to have hit a roadblock that I can't figure out with GDB or my own research.
After hours of rewrites, and hours of debugging, I finally got the code below to compile. The program is supposed to take a credit card number as an input, and then check whether it's valid per the specifications of the assignment. I used a test number from here: PayPal Test Credit Cards
The odd thing is, when I enter an AMEX card number, it correctly produces the text "AMEX", but when I try a Visa or a Master Card, it prints "INVALID".
In GDB I broke at the Verify function and it seems to incorrectly skip these two if/else if statements without proceeding to the Checksum function even though conditions appear to be met.
if (firstDigit == 4 && totalDigits == (13 | 16) && Checksum(cardNumber, totalDigits) == 0) // checks for a valid Visa.
...
else if (firstDigit == 5 && secondDigit == (1 | 2 | 3 | 4 | 5) && totalDigits == 16 && Checksum(cardNumber, totalDigits) == 0) // checks for a valid Mastercard.
...
The AMEX line of code that correctly executes is:
else if (firstDigit == 3 && secondDigit == (4 | 7) && totalDigits == 15 && Checksum(cardNumber, totalDigits) == 0) // checks for a valid American Express.
The arguments for all three lines seem to be formatted exactly the same. That is far as I could get in GDB though. I would print totalDigits, firstDigit, and secondDigit in GDB right before stepping through the above two non-executing lines and everything looked correct. So I'm stumped, why is the AMEX line executing, but not the others?
Thanks in advance everyone. This is the first program after hello.c that I've tried to write, so I am open to absolutely any criticism or suggestions if it looks like I'm doing something weird/wrong.
Full code:
checker.c
#include <stdio.h>
#include <stdlib.h>
int MAX = 16;
int* DigitSort(unsigned long long x, int* array);
int Verify(int* array);
int main (void)
{
int* output = malloc (sizeof(int) * (MAX + 2)); // creates a blank array for the individual digits of the card number.
unsigned long long userInput = 0;
do
{
printf("Please enter a credit card number:\n");
scanf("%lld", &userInput);
}
while (userInput <= 0); // checks to make sure the user entered a number.
switch(Verify(DigitSort(userInput, output))) // sorts the user's input into individual digits and verifies the card type and validity.
{
case 1 :
printf("VISA\n");
break;
case 2 :
printf("MASTERCARD\n");
break;
case 3 :
printf("AMEX\n");
break;
case 0 :
printf("INVALID\n");
break;
default :
printf("INVALID\n");
}
free(output);
return 0;
}
int Verify(int* array) // verifies whether or not a card number is valid. Must pass the function a sorted array of individual digits.
{
int* cardNumber = array;
int firstDigit = cardNumber[0];
int secondDigit = cardNumber[1];
int totalDigits = 0;
int Checksum(int* cardNumber, int totalDigits);
int i = 0;
while (firstDigit >= 1 && cardNumber[i] >= 0) // this step counts the number of digits in the array.
{
totalDigits = totalDigits + 1;
i++;
}
if (firstDigit == 4 && totalDigits == (13 | 16) && Checksum(cardNumber, totalDigits) == 0) // checks for a valid Visa.
{
return 1;
}
else if (firstDigit == 5 && secondDigit == (1 | 2 | 3 | 4 | 5) && totalDigits == 16 && Checksum(cardNumber, totalDigits) == 0) // checks for a valid Mastercard.
{
return 2;
}
else if (firstDigit == 3 && secondDigit == (4 | 7) && totalDigits == 15 && Checksum(cardNumber, totalDigits) == 0) // checks for a valid American Express.
{
return 3;
}
else // if the card number doesn't match any of the above conditions or fails the checksum, an 'I' for Invalid is returned.
{
return 0;
}
}
int* DigitSort(unsigned long long x, int* array) // takes a long long as input and sorts it into individual digits
{
int* arrayReversed = malloc (sizeof(int) * (MAX + 2)); // creates a new array to hold the reversed order of digits.
int i = 0;
arrayReversed[0] = 0;
if (i < (MAX - 1) && x >= 10)
{
do
{
arrayReversed[i] = x % 10;
x = x / 10;
i++;
}
while (i < (MAX -1) && x >= 10);
}
if (i < MAX && x >= 1 && x <= 9)
{
arrayReversed[i] = (int) x;
x = (x - x);
}
if (x == 0)
{
int j = 0;
do
{
array[j] = arrayReversed[i]; // sorts the digits from the reversed array and places them into the sorted array.
j++;
i--;
}
while (j < MAX && i >= 0);
array[j] = -1;
}
free(arrayReversed);
return array;
}
int Checksum(int* cardNumber, int totalDigits)
{
int sum1 = 0;
int sum2 = 0;
int i = (totalDigits - 2);
int j = (totalDigits - 1);
while (i >= 0)
{
sum1 = ((cardNumber[i] * 2)%10) + ((cardNumber[i] * 2)/10) + sum1;
i -= 2;
}
while (j >= 0)
{
sum2 = (cardNumber[j] + sum2);
j -= 2;
}
if (((sum1 + sum2) % 10) == 0)
{
return 0;
}
else
{
return 1;
}
}
Your first problem is here:
if (firstDigit == 4 && totalDigits == (13 | 16) && ...
You need to write:
if (firstDigit == 4 && (totalDigits == 13 || totalDigits == 16) && ...
Your first check is looking for 0x1D == 29 as the number of digits (because, as paisanco points out in a comment, the | operator is the bitwise OR operator), and no credit card needs 29 digits (yet, and not for a long time to come). Note the extra parentheses for clarity and accuracy. Don't mess around risking removing them — the code won't work properly again. And in general, be explicit if your condition has both && and || operators and use parentheses to group terms explicitly.
You have similar problems elsewhere. As it happens, (4 | 7) is the same value as 7, so the condition works when the second digit is 7 (but not when it is 4). But it doesn't mean what you intended it to mean.
Computer languages don't work the same as human languages. Get used to writing out the condition somewhat more verbosely. Some other languages provide shorthands for these conditions; C is not such a language.

Converting an Int to a Bool

I am having issues creating a loop that checks to see if 5 variables are between the variables 10 and 50. I believe I have set up the correct coding, but I am getting an error saying that I cannot convert an int to a bool. Here is what I currently have:
string userName = "";
int v1, v2, v3, v4, v5 = 0;
float avg;
float variance;
Console.WriteLine("What is your name?");
userName = Console.ReadLine();
Console.WriteLine();
int i = 1;
while (i <= 5)
{
int InputCheck = 0;
Console.WriteLine("Please input a number {0} between 10 and 50;", i);
InputCheck = Convert.ToInt32(Console.ReadLine());
if (InputCheck >= 10 && InputCheck <= 50)
{
if (i >= 10 && i <= 50)
i++;
if (i != 1)
{
InputCheck = v1;
}
if (i != 2)
{
InputCheck = v2;
}
if (i == 3)
{
InputCheck = v3;
}
if (i == 4)
{
InputCheck = v4;
}
if (i == 5)
{
InputCheck = v5;
}
if (InputCheck < 10 || InputCheck > 50)
{
Console.WriteLine("The number you entered is either to high or to low please re-enter a number:");
}
}
Any help would be greatly appreciated.
I'm not 100% sure, but I think your error comes from this line:
Console.WriteLine("Please input a number {0} between 10 and 50;", i);
You are giving an int 'i', where it expects a boolean.
Maybe this will help: http://msdn.microsoft.com/en-us/library/70x4wcx1.aspx?cs-save-lang=1&cs-lang=vb#code-snippet-2
As for the rest of your code:
Calamar888 is correct, the first if statement you are using for 'i'
will never evaluate as true.
Also, the ifs that follow ( if(i !=1),
etc) will evaluate to true more than once, overwriting values that
you have already saved ( i != 1 when i = 2, 3, 4, or 5).
Inside those if statements you are changing the value of 'InputCheck', not saving it.
You should consider using arrays to make your program shorter
Your else "if (InputCheck < 10 || InputCheck > 50)" should not be inside the first if, it will never be true
Assuming that you declare:
int v[5]; /* creates array v[0], v[1], ... v[4] */
int i = 0;
while (i<=4){
/* internal code */
}
Something like this should work:
/* internal code */
if (InputCheck >= 10 && InputCheck <= 50)
{
v[i] = InputCheck;
i++;
}
else if (InputCheck < 10 || InputCheck > 50)
{
Console.WriteLine("The number you entered is either to high or to low please re-enter a number:");
}

Resources