Validation 2 digits minimum C language - c

My job is to make a password validator with:
No spaces allowed
1 Symbol
2 Digits
Minimum 6 characters
Maximum 10 characters
Just the above restrictions, so far I have done alone the 1, 2, 4, 5 and I can't solve the third requirement about 2 digits. I can only do so with 1 digit so how do I to do it with 2? I think regex doesn't work like C++ and C# in C. Here is my code:
#include <stdio.h>
#include <string.h>
int main(){
char pass[11];
int stop;
printf("Give password:\n");
scanf(" %[^\n]s",pass);
do{
if(strlen(pass)<6){
stop=0;
printf("Too short password.");
}
else if(strlen(pass)>10){
stop=0;
printf("Too long password.");
}
else if(strchr(pass, ' ')){
stop=0;
printf("No spaces.");
}
else if((strchr(pass, '$')==NULL && strchr(pass, '#')==NULL && strchr(pass, '#')==NULL && strchr(pass, '!')==NULL && strchr(pass, '%')==NULL && strchr(pass, '*')==NULL)){
stop=0;
printf("Must give at least one of $, #, #, !, %% or *.");
}
else{
stop=1;
printf("Your password is %s\n", pass);
}
}while(stop=0);
return 0;}

That's not really a regex. What you have there is basically a small program that checks its input for different conditions. So, in the same manner, to make sure you have 2 digits, let's create a function that counts the number of digits. Keep in mind that in ASCII the digits 0 to 9 are in a continuous block (this is very important, as you will see).
int countDigits(char *input) {
int digitCount = 0;
for (int i = 0; i < strlen(input); i++) // for every character
if (input[i] >= '0' && input[i] <= '9') // if it is a digit
digitCount++;
return digitCount;
}
I've written this function this way to introduce show some character manipulation techniques. It would have been better if the condition would be:
if (isdigit(input[i]))
for portability reasons. Note that the function isdigit is defined in the ctype.h header. There is still some room for improvement:
int countDigits(char *input) {
int digitCount = 0;
int noOfCharacters = strlen(input); // avoid strlen() being called
// for every iteration
for (int i = 0; i < strlen(input); i++) // for every character
digitCount += isdigit(input[i]);
return digitCount;
}
Now you need just to take this function and check if it returns 2 for the input you've got.

No reason for small-ish buffer. Test #5 cannot have been done properly with pass[11]
// char pass[11];
char pass[100];
Dangerous to use unlimited length input. Change to
scanf(" %99[^\n]",pass);
Count the digits
int cnt = 0;
for (i=0; pass[i]; i++) {
if (pass[i] >= '0' && pass[i] <= '9') cnt++;
}
if (cnt != 2) BadPsss();

RegEx search [^0-9] the input string and replace globally with nothing.
Verify the remaining string to be two characters long.

Related

Why did I get Wrong Answer on this problem(Uva OJ 455)

I'm crazy about this problem (Uva 455):
A character string is said to have period k if it can be formed by
concatenating one or more repetitions of another string of length k.
For example, the string ”abcabcabcabc” has period 3, since it is
formed by 4 repetitions of the string ”abc”. It also has periods 6
(two repetitions of ”abcabc”) and 12 (one repetition of
”abcabcabcabc”).
Write a program to read a character string and
determine its smallest period.
Input
The first line oif the input file
will contain a single integer N indicating how many test case that
your program will test followed by a blank line. Each test case will
contain a single character string of up to 80 non-blank characters.
Two consecutive input will separated by a blank line.
Output
An
integer denoting the smallest period of the input string for each
input. Two consecutive output are separated by a blank line.
Sample Input
1
HoHoHo
Sample Output
2
I've checked all test cases I could imagine and all of them returned correct result, but I still get Wrong Answer on the online judge. Where did I go wrong?
(English is not my native language; please excuse typing or syntax errors.)
#include <stdio.h>
#include <string.h>
#define maxn 85
int check(char* s, int per){
for(int i = 0; i < strlen(s) - per; i++){
if(s[i + per] != s[i]) return 0;
}
return 1;
}
int main(){
int T;
scanf("%d", &T);
char s[maxn];
while(T--){
scanf("%s", s);
int len = strlen(s);
bool OK = false;
for(int i = 1; i <= len/2 && (len % i == 0); i++){//That's wrong.
if(check(s, i)){
printf("%d\n", i);
OK = true;
break;
}
}
if(!OK) printf("%d\n", len);
if(T) printf("\n");
}
return 0;
}
The problem is in for(int i = 1; i <= len/2 && (len % i == 0); i++). You are stopping as soon as you encounter an i that doesn't divide len, instead of skipping it.
Write the loop as:
for (int i = 1; i <= len/2; i++) {
if (len % i != 0) continue;
...
}

Bucky Robert's first task, validating password with isupper(), isdigit(), and the containment of a '$' character

Ok so I have been watching Bucky Robert's tutorials on C programming and the first task he gives the viewers is to make a program that checks if a password has at least one upper case character, one digit, and one dollar sign.
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <math.h>
int main()
{
int upper = 0;
int digit = 0;
int dollar = 0;
char password[16];
int loop = 1;
while(loop == 1){
printf("Enter your password: ");
scanf(" %s", password);
int i;
for(i = 0; i <= 16; i++){
printf(" %c", password[i]);
if(isupper(password[i])){
upper = 1;
printf("\t is upper");
}
if(isdigit(password[i])){
digit = 1;
printf("\t is digit");
}
if(password[i] == '$'){
dollar = 1;
printf("\t is dollar");
}
printf("\n");
}
if((upper == 1) && (digit == 1) && (dollar == 1)){
printf("Your password is valid\n");
loop = 0;
} else {
printf("Your password is invalid\n");
}
}
return 0;
}
The program prints this in the console after an input of 'P4sswoRd':
Enter your password: P4sswoRd
P is upper
4 is digit
s
s
w
o
R is upper
d
╨
#
ö
 
`
$ is dollar
Your password is valid
None of the passwords i entered contain the '$' character yet the program still finds a way to detect it. The reason it prints "is digit" or "is dollar" after the character was to check what had gone wrong in the code and see why the passwords were all valid. I have no idea why all those random characters are printed and I would rather know what is going wrong with my program rather than taking a new approach to the task at hand.
This loop is wrong:
for(i = 0; i <= 16; i++){
If you only type 4 characters, you should only be checking the first 4 characters of the string. This is why you're seeing lots of random characters -- those are the garbage that's in the remaining elements of password. It should be:
size_t pw_len = strlen(password);
for (i = 0; i < pw_len; i++) {
Also, remember that since arrays are zero-based, the last element of the array has the index length-1. So if you do want to process all the elements of an array declared password[16], the loop criteria should be i < 16, not i <= 16 -- that will try to access outside the array on the last iteration.
You also need to initialize the upper, digit, and dollar variables at the beginning of the while loop. Otherwise, if you type a password with numbers and $, then a new password with uppers, the second password will be called valid because it still has the digit and dollar settings from the previous password.
So it should be:
while(loop == 1){
upper = digit = dollar = 0;

Program runs too slowly with large input - C

The goal for this program is for it to count the number of instances that two consecutive letters are identical and print this number for every test case. The input can be up to 1,000,000 characters long (thus the size of the char array to hold the input). The website which has the coding challenge on it, however, states that the program times out at a 2s run-time. My question is, how can this program be optimized to process the data faster? Does the issue stem from the large char array?
Also: I get a compiler warning "assignment makes integer from pointer without a cast" for the line str[1000000] = "" What does this mean and how should it be handled instead?
Input:
number of test cases
strings of capital A's and B's
Output:
Number of duplicate letters next to each other for each test case, each on a new line.
Code:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int main() {
int n, c, a, results[10] = {};
char str[1000000];
scanf("%d", &n);
for (c = 0; c < n; c++) {
str[1000000] = "";
scanf("%s", str);
for (a = 0; a < (strlen(str)-1); a++) {
if (str[a] == str[a+1]) { results[c] += 1; }
}
}
for (c = 0; c < n; c++) {
printf("%d\n", results[c]);
}
return 0;
}
You don't need the line
str[1000000] = "";
scanf() adds a null terminator when it parses the input and writes it to str. This line is also writing beyond the end of the array, since the last element of the array is str[999999].
The reason you're getting the warning is because the type of str[10000000] is char, but the type of a string literal is char*.
To speed up the program, take the call to strlen() out of the loop.
size_t len = strlen(str)-1;
for (a = 0; a < len; a++) {
...
}
str[1000000] = "";
This does not do what you think it does and you're overflowing the buffer which results in undefined behaviour. An indexer's range is from 0 - sizeof(str) EXCLUSIVE. So you either add one to the
1000000 when initializing or use 999999 to access it instead. To get rid of the compiler warning and produce cleaner code use:
str[1000000] = '\0';
Or
str[999999] = '\0';
Depending on what you did to fix it.
As to optimizing, you should look at the assembly and go from there.
count the number of instances that two consecutive letters are identical and print this number for every test case
For efficiency, code needs a new approach as suggeted by #john bollinger & #molbdnilo
void ReportPairs(const char *str, size_t n) {
int previous = EOF;
unsigned long repeat = 0;
for (size_t i=0; i<n; i++) {
int ch = (unsigned char) str[i];
if (isalpha(ch) && ch == previous) {
repeat++;
}
previous = ch;
}
printf("Pair count %lu\n", repeat);
}
char *testcase1 = "test1122a33";
ReportPairs(testcase1, strlen(testcase1));
or directly from input and "each test case, each on a new line."
int ReportPairs2(FILE *inf) {
int previous = EOF;
unsigned long repeat = 0;
int ch;
for ((ch = fgetc(inf)) != '\n') {
if (ch == EOF) return ch;
if (isalpha(ch) && ch == previous) {
repeat++;
}
previous = ch;
}
printf("Pair count %lu\n", repeat);
return ch;
}
while (ReportPairs2(stdin) != EOF);
Unclear how OP wants to count "AAAA" as 2 or 3. This code counts it as 3.
One way to dramatically improve the run-time for your code is to limit the number of times you read from stdin. (basically process input in bigger chunks). You can do this a number of way, but probably one of the most efficient would be with fread. Even reading in 8-byte chunks can provide a big improvement over reading a character at a time. One example of such an implementation considering capital letters [A-Z] only would be:
#include <stdio.h>
#define RSIZE 8
int main (void) {
char qword[RSIZE] = {0};
char last = 0;
size_t i = 0;
size_t nchr = 0;
size_t dcount = 0;
/* read up to 8-bytes at a time */
while ((nchr = fread (qword, sizeof *qword, RSIZE, stdin)))
{ /* compare each byte to byte before */
for (i = 1; i < nchr && qword[i] && qword[i] != '\n'; i++)
{ /* if not [A-Z] continue, else compare */
if (qword[i-1] < 'A' || qword[i-1] > 'Z') continue;
if (i == 1 && last == qword[i-1]) dcount++;
if (qword[i-1] == qword[i]) dcount++;
}
last = qword[i-1]; /* save last for comparison w/next */
}
printf ("\n sequential duplicated characters [A-Z] : %zu\n\n",
dcount);
return 0;
}
Output/Time with 868789 chars
$ time ./bin/find_dup_digits <dat/d434839c-d-input-d4340a6.txt
sequential duplicated characters [A-Z] : 434893
real 0m0.024s
user 0m0.017s
sys 0m0.005s
Note: the string was actually a string of '0's and '1's run with a modified test of if (qword[i-1] < '0' || qword[i-1] > '9') continue; rather than the test for [A-Z]...continue, but your results with 'A's and 'B's should be virtually identical. 1000000 would still be significantly under .1 seconds. You can play with the RSIZE value to see if there is any benefit to reading a larger (suggested 'power of 2') size of characters. (note: this counts AAAA as 3) Hope this helps.

Check if input is a string (4 characters only) and if not return to input again

My aim is to accept 4-digit numbers, and 4-character strings (string should not contain digits or special characters)
If an invalid input is given the program should not terminate and it must allow the user to enter the details and continue until he wish to terminate.
I am able to find whether the input is a digit.
if(scanf("%d",&input)!=1)
{
printf("enter the number please");
... // I have option to re enter using while and flags
}
else
{
// I continue my work
...
}
To check it is four digits I have tried using the commands
i=0;
num = input;
while(num>0)
{
i = i+1;
num = num/10;
}
if(i==4){
...//I continue
}
else
printf("please enter four digit");
I have no idea of checking the same for characters. (I know how to check its length using strlen())
Please help me with the code in C. (Also help me to reduce/optimize the above logic to check whether the input is a 4-digit number)
I believe you want 2 inputs a number and a string. You can do that as
int number= 0;
char string[10] = { 0 };
do {
printf("please enter four digit");
scanf("%d", &number);
if(number >=1000 && number<= 9999)
break;
} while(1);
do {
printf("please enter four character string");
fgets(string, sizeof(string), stdin);
if(strlen(string) == 4)
break;
} while(1);
To check it is four digit number you can simply put a check whether the number lies between 1000 and 9999. (I am assuming you don't want the number to start with 0.)
strtol can help:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char s[32], *p;
int x;
fgets(s, sizeof(s), stdin);
if ((p = strchr(s, '\n')) != NULL)
*p = '\0';
x = (int)strtol(s, &p, 10);
if ((p - s) == 4) {
printf("%d\n", x);
} else {
printf("Please enter four digit\n");
}
return 0;
}
char input[16];
int ok = 1, k = 0;
if (scanf("%s", input) > 0 && strlen(input) == 4) {
// check if it's a word
for (; k < 4; k++)
if (!isalpha(input[k])) {
// check if it's a number
for (int k = 0; k < 4; k++)
if (!isdigit(input[k]))
ok = 0;
break;
}
}
else ok = 0;
if (!ok)
printf("invalid input, please enter a 4-digit number or 4-letter word");
else {
printf("valid input");
...
}
You can use gets()1 fgets() to get the whole line and check line length. If the first character is between '0' and '9' then check the remaining if they are 3 numbers too. If the first character is a valid character in string then check the 3 remaining chars if it's also valid in string.
1See Why is the gets function so dangerous that it should not be used?

How do I force user to input a positive integer?

Force user to input a positive integer and put user in a loop till they do.
So I want everything including characters not allowed just over > 0
I tried the following:
while (i < 0) do {
printf("please input a number that's positive");
scanf("%d", i);
}
For positive integer use the following code
int i;
do
{
printf("please input a number that's positive");
scanf("%d", &i);
}while (i < 0);
The c language provides no error checking for user input. The user is expected to enter the correct data type. For instance, if a user entered a character when an integer value was expected, the program may enter an infinite loop or abort abnormally.
Both of these while functions manage the numbers, the int k is the set integer which can only be set below 20, the first while loop makes a statement that calls for another scan if the number is greater than 20
and the second loop prints a k*k box.
Hope this helps.
int main ( )
{
int i, j,k;
printf("Please enter Box size:\n\n");
scanf("%d",&k);
while(k>20){
printf("Please enter a value below 20\n\n");
scanf("%d"),&k;
}
while(k<=20)
{
for (i = 0; i < k; i++)
{
printf("\n");
for (j = 0; j < k; j++)
{
printf("#");
}
}
return 0;
}
}
I would do this: declare char term and int wrong = 0.
do {
printf("Enter a number: ");
fflush(stdin);
if (scanf("%d%c", &n, &term) != 2 || term != '\n' || n <= 0) {
printf("Only positive numbers.\n");
wrong = 1;
}
else {
wrong = 0;
//do something here if correct;
}
} while (wrong);
The code above detects invalid input if the user entered a mixture of characters and numbers, or negative numbers (and zero).
However, it doesn't detect if the user entered trailing zeros in front followed by valid digits eg. 001or 00000738. If anyone else could figure this out, please share below. Thanks! :)
Here is another alternative of a function which takes in a char str[20] (of say, maybe 20 elements), analyses the string to check for positive integers, and returns a 0 or 1 accordingly. Lastly, convert that string to an integer using atoi().
int checkPositiveIntegers(char str[]) {
char *ptr = str;
if (*ptr == '-' || *ptr == '0') //checks for negative numbers or zero
return 1;
else {
do {
if (isdigit(*ptr) == 0) { //checks for non-digit at ptr location; isdigit() returns 0 if non-digit
return 1;
break;
}
ptr++;
} while (*ptr != '\0' && *ptr != '\n');
return 0; //returns 0 if positive integer
}
}
So the function only accepts positive numbers from 1 to 9,999,999,999,999,999,999 (up to 19 digits if char str[] holds 20 elements).
However, if you converted the string back to int n = atoi(str);, the maximum value it could reach would be 2,147,483,647 since n is declared as a signed integer. Play around with different datatypes for exploration.
Hope this helps! :)

Resources