Validation of infinite input char \ number - c

I need to get a valid number from the user between 0-9 without duplicates.
The valid number can have any number of digit, from 1 to 10.
If the user type "space" or any kind of char, then the input is invalid.
My algorithm :
1) Create an array of char in size of 10, then initialize all cells to '0'.
2) For every char that reads from the user, check if the char actually between 0-9.
2.1) If true: count the respectively cell number +1.
2.2) Else "error".
2.3) If I get to a cell that already has +1, means this number already exist, then "error".
Now a few questions about my idea:
1) Is there any better\easy algorithm to do that?
2) The user doesn't type char by char, means I can get an infinite char length, so where do I store everything?

The answer to 2) is: you don't store the characters at all, you process them one by one. You only need storage to remember which digits you have already seen. I'd do it like this:
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char seen[10] = { 0 };
int c, loops;
for (loops = 0; (c = getchar()) != EOF && loops < 10; ++loops)
{
if (!isdigit(c)) {
printf ("Not a digit: %c\n", c);
break;
}
c -= '0';
if (seen[c]) {
printf ("Already seen: %d\n", c);
break;
}
seen[c] = 1;
}
return 0;
}
Try to modify this program as an exercise: reduce the storage requirements of the seen[] array. As written it uses one byte per digit. Make the program use only one bit per digit.

Related

How to count the number of distinct characters in common between two strings?

How can a program count the number of distinct characters in common between two strings?
For example, if s1="connect" and s2="rectangle", the count is being displayed as 5 but the correct answer is 4; repeating characters must be counted only once.
How can I modify this code so that the count is correct?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int i,j,count=0;
char s1[100],s2[100];
scanf("%s",s1);//string 1 is inputted
scanf("%s",s2);//string 2 is taken as input
for(i=1;i<strlen(s1);i++)
{
for(j=1;j<strlen(s2);j++)
{
if(s1[i]==s2[j])//compare each char of both the strings to find common letters
{
count++;//count the common letters
break;
}
}
}
printf("%d",count);//display the count
}
The program is to take two strings as input and display the count of the common characters in those strings. Please let me know what's the problem with this code.
If repeating characters must be ignored, the program must 'remember' the character which were already encountered. You could do this by storing the characters which were processed into a character array and then consult this array while processing the other characters.
You could use a counter variable to keep track of the number of common characters like
int ctr=0;
char s1[100]="connect", s2[100]="rectangle", t[100]="";
Here, t is the character array where the examined characters will be stored. Its size is made to be same as the size of the largest of the other 2 character arrays.
Now use a loop like
for(int i=0; s1[i]; ++i)
{
if(strchr(t, s1[i])==NULL && strchr(s2, s1[i])!=NULL)
{
t[ctr++]=s1[i];
t[ctr]=0;
}
}
t initially has an empty string. Characters which were previously absent in t are added to it via the body of the loop which will be executed only if the character being examined (ie, s1[i]) is not in t but is present in the other string (ie, s2).
strchr() is a function with a prototype
char *strchr( const char *str, int c );
strchr() finds the first occurrence of c in the string pointed to by str. It returns NULL if c is not present in str.
Your usage of scanf() may cause trouble.
Use
scanf("%99s",s1);
(where 99 is one less than the size of the array s1) instead of
scanf("%s",s1);
to prevent overflow problems. And check the return value of scanf() and see if it's 1. scanf() returns the number of successful assignment that it made.
Or use fgets() to read the string.
Read this post to see more about this.
And note that array indexing starts from 0. So in your loops, the first character of the strings are not checked.
So it should've been something like
for(i=0;i<strlen(s1);i++)
instead of
for(i=1;i<strlen(s1);i++)
Here's a solution that avoids quadratic O(N²) or cubic O(N³) time algorithms — it is linear time, requiring one access to each character in each of the input strings. The code uses a pair of constant strings rather than demanding user input; an alternative might take two arguments from the command line and compare those.
#include <limits.h>
#include <stdio.h>
int main(void)
{
int count = 0;
char bytes[UCHAR_MAX + 1] = { 0 };
char s1[100] = "connect";
char s2[100] = "rectangle";
for (int i = 0; s1[i] != '\0'; i++)
bytes[(unsigned char)s1[i]] = 1;
for (int j = 0; s2[j] != '\0'; j++)
{
int k = (unsigned char)s2[j];
if (bytes[k] == 1)
{
bytes[k] = 0;
count++;
}
}
printf("%d\n",count);
return 0;
}
The first loop records which characters are present in s1 by setting an appropriate element of the bytes array to 1. It doesn't matter whether there are repeated characters in the string.
The second loop detects when a character in s2 was in s1 and has not been seen before in s2, and then both increments count and marks the character as 'no longer relevant' by setting the entry in bytes back to 0.
At the end, it prints the count — 4 (with a newline at the end).
The use of (unsigned char) casts is necessary in case the plain char type on the platform is a signed type and any of the bytes in the input strings are in the range 0x80..0xFF (equivalent to -128..-1 if the char type is signed). Using negative subscripts would not lead to happiness. The code does also assume that you're working with a single-byte code set, not a multi-byte code set (such as UTF-8). Counts will be off if you are dealing with multi-byte characters.
The code in the question is at minimum a quadratic algorithm because for each character in s1, it could step through all the characters in s2 only to find that it doesn't occur. That alone requires O(N²) time. Both loops also use a condition based on strlen(s1) or strlen(s2), and if the optimizer does not recognize that the value returned is the same each time, then the code could scan each string on each iteration of each loop.
Similarly, the code in the other two answers as I type (Answer 1 and Answer 2) are also quadratic or worse because of their loop structures.
At the scale of 100 characters in each string, you probably won't readily spot the difference, especially not in a single iteration of the counting. If the strings were bigger — thousands or millions of bytes — and the counts were performed repeatedly, then the difference between the linear and quadratic (or worse) algorithms would be much bigger and more easily detected.
I've also played marginally fast'n'loose with the Big-O notation. I'm assuming that N is the size of the strings, and they're sufficiently similar in size that treating N₁ (the length of s1) as approximately equal to N₂ (the length of s2) isn't going to be a major problem. The 'quadratic' algorithms might be more formally expressed as O(N₁•N₂) whereas the linear algorithm is O(N₁+N₂).
Based on what you expect as output you should keep track which char you used from the second string. You can achieve this as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int i, j, count = 0, skeep;
char s1[100], s2[100], s2Used[100]{0};
scanf("%s", s1); //string 1 is inputted
scanf("%s", s2); //string 2 is taken as input
for (i = 0; i<strlen(s1); i++)
{
skeep = 0;
for (j = 0; j < i; j++)
{
if (s1[j] == s1[i])
{
skeep = 1;
break;
}
}
if (skeep)
continue;
for (j = 0; j<strlen(s2); j++)
{
if (s1[i] == s2[j] && s2Used[j] == 0) //compare each char of both the strings to find common letters
{
//printf("%c\n", s1[i]);
s2Used[j] = 1;
count++;//count the common letters
break;
}
}
}
printf("%d", count);//display the count
}

Variable value is reset inside a loop in C

I have a case in which I have to identify if a number is positive, negative or zero and count how many times each of these cases happen. The code I wrote is this:
#include
#include
#include
using namespace std;
int main(int argc, char *argv[])
{
char opcion = 's';
int positivos = 0;
int negativos = 0;
int ceros = 0;
//int ceros2 = 0;
int temporal;
do{
printf("Enter a number: ");
scanf("%d",&temporal);
if(temporal >= 0)
{
if(temporal==0)
{
ceros ++;
}
else
{
positivos ++;
}
}
if(temporal < 0)
{
negativos ++;
}
printf("Do you want to enter another number? (s/n)");
scanf("%s",&opcion);
}
while(opcion == 's' || opcion=='S');
printf("you have %d possitive numbers \n",positivos);
printf("you have %d negative numbers \n",negativos);
printf("you have %d zero \n",ceros);
return 0;
}
If I run the code as it is, the number of zeroes will always be zero, but if you uncoment the line 13 int ceros2 = 0; (my logic was "let's declare another initializaed variable and see what happens") then the program will count the zeroes as expected. Why do i have to declare a useless variable in order to the program make the count?
What is C compiler doing with the code that does not respect the value of the last declared and initialized variable unless you declare a new initialized variable?
You are asking scanf() to read in a C string, which, if the user types a character, will contain both that character and the null terminator. You have provided only a single character's worth of storage. So, the null terminator doesn't fit but it gets stored somewhere. As it happens, it's clobbering other data that happens to be next to opcion on the stack and that happens to be your ceros variable.
Declaring another variable has reorganized the layout of data on the stack and changes what gets clobbered, so you're not noticing it. It's still writing out of bounds, though.
You could use a format string of "%c" to read a single character.

Writing a program in C with the function isAlphabetic to determine if a string strictly contains alphabetic letters or not

This is what I have so far.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int value;
char c='Z';
char alph[30]="there is a PROF 1 var orada";
char freq[27];
int i;
// The function isAlphabetic will accept a string and test each character to
// verify if it is an alphabetic character ( A through Z , lowercase or uppercase)
// if all characters are alphabetic characters then the function returns 0.
// If a nonalphabetic character is found, it will return the index of the nonalpabetic
// character.
value = isAlphabetic(alph);
if (value == 0)
printf("\n The string is alphabetic");
else
printf("Non alphabetic character is detected at position %d\n",value);
return EXIT_SUCCESS;
}
int isAlphabetic(char *myString) {
}
What I'm confused is how will I have the program scan through a string to detect exactly where a non alphabetic character is, if any? I'm guessing it'll first involve counting all the characters in a string first?
Not going to provide the answer via code (as someone else did), but consider:
A string in C is nothing more than an array of characters and a null terminator.
You can iterate through each item in an array using [] (i.e., input[i]) to check its value against an ASCII table for example.
Your function can exit as soon as it finds one value that is not alphabetic.
There are certainly other ways to solve this problem, but my assumption is that at this level, your professor would be a bit suspicious if you started using a bunch of libraries / tools you haven't been taught.
Let's take your questions one at a time:
...how will I have the program scan through a string...
"Scan through a string" means you skin the cat with a loop:
char xx[] = "ABC DEF 123 456";
int ii;
/* for, while, do while; pick your poison */
for (ii = 0; xx[ii] != '\0'; ++ii)
{
/* Houston, we're scanning. */
}
...to detect...
"Detect" means you skin the cat with a comparison of some sort:
char a, b;
a == b; /* equality of two char's */
a >= b; /* greater-than-or-equal-to relationship of two char's */
a < b; /* I'll bet you can guess what this does now */
...exactly where a non alphabetic character is...
Well by virtue of scanning you'll know "exactly where" due to your index.
Scan from the first alphabet to the last alphabet. Begin with a counter variable set to 0.
Each time you move to next character, do counter++;this will give you the index of non alphabet.
If you find any non-alphabet character,return counter there itself.
I will give you a hint :
#include <stdio.h>
int main()
{
char c = '1';
printf("%d",c-48); //notice this
return 0;
}
Output : 1
Should be more than enough to solve it on your own now :)

Converting Character Array to Integer Array in C for ISBN Validation

I really hope someone can give a well explained example. I've been searching everywhere but can't find a proper solution.
I am taking an introduction to C Programming class, and our last assignment is to write a program which validates a 10 digit ISBN with dashes... The ISBN is inputted as a string in a CHAR array. From there I need to separate each digit and convert them into an integer, so I can calculated the validity of the ISBN. On top of that, the dashes need to be ignored..
My thought process was to create an INT array and then use a loop to store each character into the array, and pass it through the atoi() function. I also tried using an IF statement to check each part of the CHAR array to see if it found a dash. If it did find one, it would skip to the next spot in the array. It looked something like this:
int num[12], i = 0, j = 0, count = 0;
char isbn[12];
printf ("Enter an ISBN to validate: ");
scanf ("%13[0-9Xx-]%*c", &isbn);
do {
if (isbn[i] == '-') {
i++;
j++;
}
else {
num[i]= atoi(isbn[j]);
i++;
j++;
}
count++;
} while (count != 10);
But that creates a segmentation fault, so I can't even tell if my IF statement has actually filtered the dashes....
If someone could try and solve this I'd really appreciate that. The Assignment was due Dec 4th, however I got an extension until Dec 7th, so I'm pressed for time.
Please write out the code in your explanation. I'm a visual learner, and need to see step by step.
There's obviously a lot more that needs to be coded, but I can't move ahead until I get over this obstacle.
Thanks in advance!
First of all, your definition of isbn is not sufficient to hold 13 characters; it should therefore be 14 chars long (to also store the terminating '\0').
Second, your loop is overly complicated; three loop variables that maintain the same value is redundant.
Third, the loop is not safe, because a string might be as short as one character, but your code happily loops 10 times.
Lastly, converting a char that holds the ascii value of a digit can be converted by simply subtracting '0' from it.
This is the code after above improvements have been made.
#include <stdio.h>
int main(void)
{
int num[14], i;
char isbn[14], *p;
printf("Enter an ISBN to validate: ");
scanf("%13[0-9Xx-]%*c", &isbn);
// p iterates over each character of isbn
// *p evaluates the value of each character
// the loop stops when the end-of-string is reached, i.e. '\0'
for (p = isbn, i = 0; *p; ++p) {
if (*p == '-' || *p == 'X' || *p == 'x') {
continue;
}
// it's definitely a digit now
num[i++] = *p - '0';
}
// post: i holds number of digits in num
// post: num[x] is the digit value, for 0 <= x < i
return 0;
}

C: extract numbers from a string

I have a bunch of strings structured like this one
Trim(2714,8256)++Trim(10056,26448)++Trim(28248,49165)
and what I want to do is to save all the numbers into an array (for the sake of this answer let's say I want to save the numbers of just one string).
My plan was to find the the position of the first digit of every number and just read the number with sscanf, but as much as I've thought about it, I couldn't find a proper way to do so. I've read a lot about strstr, but it is used to search for a string into another string, so I should search for the exact number or do 10 cases to cover from 0 to 9.
Thanks in advance for your support!
You could try something like this:
Walk the string until you find the first digit (use isdigit)
Use strtoul to extract the number starting at that position
strtoul returns the number
the second argument (endptr) points to the next character in the string, following the extracted number
Rinse, repeat
Alternatively you could tokenize the string (using "(,+)") and try to strtoul everything.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main() {
int arr[10], idx=0, d, l=0;
char *p, *str = "Trim(2714,8256)++Trim(10056,26448)++Trim(28248,49165)";
for (p = str; *p != 0; p+=l) {
l = 1;
if (isdigit(*p)){
sscanf(p, "%d%n", &d, &l);
arr[idx++] = d;
}
}
for (l=0; l<idx; l++) {
printf("%d\n", arr[l]);
}
return 0;
}
You can also try using YACC or Lex, which will format your string as you want.
Here is how I would think about the code:
start loop over source array characters
if the character in the current position (of the source array) is a digit
copy it to the destination array (in the current position of the destination array)
move to the next position in the destination array
move to the next position in the source array
if the end of the source string is reached, exit loop
make sure that the destination string is terminated properly (i.e. by '\0')
Note that we are counting with two different counters one for the source array which will increment with every loop iteration and the other for the destination array and will only increment if a digit is found
checking of a character is a digit or not can be done using the function "isdigit()" but it will require the header file ctype.h
Another way to check if the character is a digit is by checking its value in reference to the ASCII table
character '0' equals 48 and character '9' equals 57. So if the character is within that range it is a digit, other wise it is a character. You can actually compare directly with the characters.
if (character >= '0' && character =< '9') printf("%c is a digit", character);
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main() {
int array[8], count=0, data;
const char *s = "Trim(+2714,8256)++Trim(10056,26448)++Trim(28248,49165)";
char *p;
while(*s) {
if(isdigit(*s) || *s=='-' && isdigit(s[1])){
data = strtol(s, &p, 10);
s = p;
array[count++] = data;
} else
++s;
}
{//test print
int i;
for(i=0;i<count;++i)
printf("%d\n", array[i]);
}
return 0;
}

Resources