String terminator in character array in C - c

I'm trying to make a program to decide the validity of a password, based on a set of rules.
Here is what I have:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <math.h>
int main()
{
int uppercase = 0;
int length = 0;
int numbers = 0;
int others = 0;
char password[13];
char yesOrNo;
printf("Your password must be 8-12 characters long.\n"
"It must contain at least one symbol, uppercase letter, and number.\n\n");
COMEBACK:
printf("Please enter your password:");
scanf(" %s", &password);
while (password != 'NULL') { // Tried 0 here, tried '\0', but to no avail.
if (isalpha(password)) {
length += 1;
if (isupper(password)) {
uppercase += 1;
}
}
else if (isdigit(password)) {
numbers += 1;
length += 1;
}
else {
length += 1;
}
// This is just a test, to see if it was working.
printf("%d - %d - %d - %d --- %s",
uppercase, length, numbers, others, password);
}
if ((uppercase > 0) && (numbers > 0)
&& (length >= 8) && (length <= 12) && (others > 0)) {
printf("Good job, you've done your password correctly.");
} else {
printf("%d - %d - %d - %d --- %s \t Incorrect..",
uppercase, length, numbers, others, password); // Same thing here.
scanf("%s", &yesOrNo);
switch (yesOrNo) {
case 'y':
goto COMEBACK;
break;
case 'n':
printf("Sorry you're dumb man..");
break;
default:
printf("Please enter a valid password.");
}
}
return 0;
}
The problem I am having is, the while loop never ends because it can't seem to find the terminator for my password array. I've inputted '\0' as well as just '0'. But I still can't figure it out. Any help is appreciated. Thanks.

This code:
while (password != 'NULL') {
should be generating compiler warnings galore. The multicharacter literal is non-portable and should not be compared with a pointer.
You might need:
char *ptr = password;
while (*ptr != '\0') {
...
ptr++;
}
or (C99 or later):
for (char *ptr = password; *ptr != '\0'; ptr++)
{
...
}
and use *ptr to identify the character (or, often, (unsigned char)*ptr since plain char is often signed and isalpha() et al require a positive value or EOF as the input value). If you don't have C99, you can declare char *ptr; outside the loop and remove the char * inside the loop control.
You have:
if (isalpha(password)) {
Since password is an array, you're passing a fixed pointer to a function that requires a non-pointer (int) value. I'd probably add inside the loop:
{
unsigned char uc = *ptr;
if (isalpha(uc))
...
Note that you probably only need one length++; for all the cases.
Also note that no password will ever satisfy the 'at least one symbol' criterion because you never increment others.
And the goto can be replaced by a while() loop which can detect EOF as well:
while (scanf("%12s", password) == 1)
{
length = others = uppercase = numbers = 0; // Ignore previous attempts
for (char *ptr = password; *ptr != '\0'; ptr++)
{
unsigned char uc = *ptr;
length++;
...character testing code...
}
...validity checking code...
}
While you're learning C, assume that the compiler warnings are solid errors. It knows more about C than you do at this stage.

password is an array. It will never be NULL. But it can contain a null-terminator, which is probably what you're after. Just check if password[0] == '\0'.

Related

Code in C where it prints from 0 to 100 then asks if user wants to see it again

I'm trying to make a program in C where it prints from 0 to 100 then asks the user to print it again. It's not working.
#include <stdio.h>
#include <string.h>
int main()
{
int num;
char resposta[0];
resposta[0] = 's';
num = 0;
do
{
for (int i = 0; i < 100; i++)
{
num += 1;
printf("%i\n", num);
printf("Repetir?s/n\n");
scanf("%c", resposta[0]);
}
} while ((strcmp(resposta[0], "S") == 0) || (strcmp(resposta[0], "s") == 0));
return 0;
}
when declaring an array in C, the number in the brackets [] is not the index number, it is the total number of elements contained within the array. Setting char resposta[0]; means that resposta contains no elements.
This is different from when accessing elements, which uses a zero-index. So running scanf("%c", resposta[0]); is trying to access the first element, but there are zero elements within resposta, so that's likely why this isn't working.
I also figure I should add that it is entirely possible to just create a char variable that is not an array, since it seems you only need the one character. Just do char resposta; without the brackets.
Some more info on Arrays if you're interested: W3Schools
There are many issues.
You have an array that can contains 0 elements which is rather pointless, you want char resposta[1].
But you don't want an array of chars anyway. You're using the %c specifier you need a single char instead of an array of chars.
You're mixing up strings and chars. Change strcmp(resposta[0], "S")==0 to resposta == 'S', provided you have declared char resposta;.
You're asking the user if he wants to start over again in the for loop which is probably not what you want.
Basically you want this (untested code):
int main() {
char resposta;
resposta = 's';
int num = 0;
do {
num = 0;
for (int i = 0; i < 100; i++) {
num += 1;
printf("%i\n", num);
}
printf("Repetir?s/n\n");
scanf("%c", &resposta); // not the useage of the & operator here
} while (resposta == 'S' || resposta == 's');
}
One of the reasons it is not working is that the program stops to ask the user to continue inside the loop. Another failure is that the counter being used is not reset to zero for the second and subsequent runs. Another failure is the scanf format specifier that does not clear the newline out of the input buffer. The next 'get input' will not find an S/s to continue, but will pickup a LF and terminate the loop.
Things can be simplified if they are separated. The interaction with the user is very clearly defined and should be factored-out into its own function:
#include <stdio.h>
int again(void) {
puts( "Repetir? " );
char ch;
return scanf( " %c", &ch ) == 1 && (ch == 'S' || ch == 's' );
}
// Edit: Just noticed the OP title says "0 to 100"
void out(void) {
int i = 0;
while( i <= 100 ) printf( "%i\n", i++ );
}
int main() {
do out(); while( again() );
return 0;
}

scanf() adds character to string

I have this code and it keeps adding what ever the guesses string is to the wordle string when I compare them, resulting in them to never be the same. How can I fix this?
#include <string.h>
int main() {
char wordle[5];
char guesses[5];
int guess = 5;
int value;
printf("Please input a secret 5 letter word:\n");
scanf("%s",wordle);
while (guess != 0){
printf("You have %d tries, please guess the word\n",guess);
scanf("%s",guesses);
value = strcmp(wordle,guesses);
if (value == 0){
printf("you win\n");
break;
}
guess = guess - 1;
}
return 0;
}```
Your program has undefined behavior. You're making two mistakes.
If your user enters 5 characters, it takes 6 characters to store the string. The program would attempt to write a null terminator into wordle[5] which is not a valid index.
Your user could enter any number of letters. You need to make sure they don't overflow your buffer.
#include <stdio.h>
#include <string.h>
int main() {
char wordle[6];
char guesses[6];
int guess = 5;
int value;
int chars_read;
do {
printf("Please input a secret 5 letter word:\n");
chars_read = scanf("%5s%*s\n", wordle);
} while(chars_read != 1 && strlen(wordle) != 5);
while (guess != 0){
do {
printf("You have %d tries, please guess the word\n", guess);
chars_read = scanf("%5s%*s\n", guesses);
} while(chars_read != 1 && strlen(wordle) != 5);
value = strcmp(wordle, guesses);
if (value == 0){
printf("you win\n");
break;
}
guess = guess - 1;
}
return 0;
}
See it in action
scanf, fscanf, sscanf, scanf_s, fscanf_s, sscanf_s
MSC24-C. Do not use deprecated or obsolescent functions
Your strings for wordle and guesses are too short. You need to make room for '\0'. They should be 6 bytes long not 5.
char wordle[6];
char guesses[6];

A program that prints even and odd characters from a string

This is for Homework
I have to write a program that asks the user to enter a string, then my program would separate the even and odd values from the entered string. Here is my program.
#include <stdio.h>
#include <string.h>
int main(void) {
char *str[41];
char odd[21];
char even[21];
int i = 0;
int j = 0;
int k = 0;
printf("Enter a string (40 characters maximum): ");
scanf("%s", &str);
while (&str[i] < 41) {
if (i % 2 == 0) {
odd[j++] = *str[i];
} else {
even[k++] = *str[i];
}
i++;
}
printf("The even string is:%s\n ", even);
printf("The odd string is:%s\n ", odd);
return 0;
}
When I try and compile my program I get two warnings:
For my scanf I get "format '%s' expects arguments of type char but argument has 'char * (*)[41]". I'm not sure what this means but I assume it's because of the array initialization.
On the while loop it gives me the warning that says comparison between pointer and integer. I'm not sure what that means either and I thought it was legal in C to make that comparison.
When I compile the program, I get random characters for both the even and odd string.
Any help would be appreciated!
this declaration is wrong:
char *str[41];
you're declaring 41 uninitialized strings. You want:
char str[41];
then, scanf("%40s" , str);, no & and limit the input size (safety)
then the loop (where your while (str[i]<41) is wrong, it probably ends at once since letters start at 65 (ascii code for "A"). You wanted to test i against 41 but test str[i] against \0 instead, else you get all the garbage after nul-termination char in one of odd or even strings if the string is not exactly 40 bytes long)
while (str[i]) {
if (i % 2 == 0) {
odd[j++] = str[i];
} else {
even[k++] = str[i];
}
i++;
}
if you want to use a pointer (assignement requirement), just define str as before:
char str[41];
scan the input value on it as indicated above, then point on it:
char *p = str;
And now that you defined a pointer on a buffer, if you're required to use deference instead of index access you can do:
while (*p) { // test end of string termination
if (i % 2 == 0) { // if ((p-str) % 2 == 0) { would allow to get rid of i
odd[j++] = *p;
} else {
even[k++] = *p;
}
p++;
i++;
}
(we have to increase i for the even/odd test, or we would have to test p-str evenness)
aaaand last classical mistake (thanks to last-minute comments), even & odd aren't null terminated so the risk of getting garbage at the end when printing them, you need:
even[k] = odd[j] = '\0';
(as another answer states, check the concept of even & odd, the expected result may be the other way round)
There are multiple problems in your code:
You define an array of pointers char *str[41], not an array of char.
You should pass the array to scanf instead of its address: When passed to a function, an array decays into a pointer to its first element.
You should limit the number of characters read by scanf.
You should iterate until the end of the string, not on all elements of the array, especially with (&str[i] < 41) that compares the address of the ith element with the value 41, which is meaningless. The end of the string is the null terminator which can be tested with (str[i] != '\0').
You should read the characters from str with str[i].
You should null terminate the even and odd arrays.
Here is a modified version:
#include <stdio.h>
int main(void) {
char str[41];
char odd[21];
char even[21];
int i = 0;
int j = 0;
int k = 0;
printf("Enter a string (40 characters maximum): ");
if (scanf("%40s", str) != 1)
return 1;
while (str[i] != '\0') {
if (i % 2 == 0) {
odd[j++] = str[i];
} else {
even[k++] = str[i];
}
i++;
}
odd[j] = even[k] = '\0';
printf("The even string is: %s\n", even);
printf("The odd string is: %s\n", odd);
return 0;
}
Note that your interpretation of even and odd characters assumes 1-based offsets, ie: the first character is an odd character. This is not consistent with the C approach where an even characters would be interpreted as having en even offset from the beginning of the string, starting at 0.
Many answers all ready point out the original code`s problems.
Below are some ideas to reduce memory usage as the 2 arrays odd[], even[] are not needed.
As the "even" characters are seen, print them out.
As the "odd" characters are seen, move them to the first part of the array.
Alternative print: If code used "%.*s", the array does not need a null character termination.
#include <stdio.h>
#include <string.h>
int main(void) {
char str[41];
printf("Enter a string (40 characters maximum): ");
fflush(stdout);
if (scanf("%40s", str) == 1) {
int i;
printf("The even string is:");
for (i = 0; str[i]; i++) {
if (i % 2 == 0) {
str[i / 2] = str[i]; // copy character to an earlier part of `str[]`
} else {
putchar(str[i]);
}
}
printf("\n");
printf("The odd string is:%.*s\n ", (i + 1) / 2, str);
}
return 0;
}
or simply
printf("The even string is:");
for (int i = 0; str[i]; i++) {
if (i % 2 != 0) {
putchar(str[i]);
}
}
printf("\n");
printf("The odd string is:");
for (int i = 0; str[i]; i++) {
if (i % 2 == 0) {
putchar(str[i]);
}
}
printf("\n");
here is your solution :)
#include <stdio.h>
#include <string.h>
int main(void)
{
char str[41];
char odd[21];
char even[21];
int i = 0;
int j = 0;
int k = 0;
printf("Enter a string (40 characters maximum): ");
scanf("%s" , str);
while (i < strlen(str))
{
if (i % 2 == 0) {
odd[j++] = str[i];
} else {
even[k++] = str[i];
}
i++;
}
odd[j] = '\0';
even[k] = '\0';
printf("The even string is:%s\n " , even);
printf("The odd string is:%s\n " , odd);
return 0;
}
solved the mistake in the declaration, the scanning string value, condition of the while loop and assignment of element of array. :)

String from user input that gets converted into a letter pattern.

Reposting because my first post was no good. I have a question that I'm not really sure how to do. I know the process I'm going for, but am not totally sure how to scan a string into an array so that each character/integer is scanned into a independent element of the array. I'll post the question and the code I have so far, and any help would be appreciated.
Question:
Assume that we have a pattern like the following: ([n][letter])+ in which n is an integer number and letter is one of the lowercase letters from a-z. For example, 2a and 3b are valid expressions based on our pattern. Also, “+” at the end of the pattern means that we have at least one expression (string) or more than one expression attached. For instance, 2a4b is another valid expression which is matched with the pattern. In this question, we want to convert these valid expressions to a string in which letters are repeated n times.
o Read an expression (string) from user and print the converted version of the expression in the output.
o Check if input expression is valid. For example, 2ab is not a valid expression. If the expression is not valid, print “Invalid” in the output and ask user to enteranother expression.
o Sample input1 = “2a”, output = aa
o Sample input2 = “2a3b”, output = aabbb
o You will receive extra credit if you briefly explain what concept or theory you can use to check whether an expression is valid or not.
What I have so far:
#include <stdio.h>
int main()
{
int size, i, j;
char pattern[20];
char vowel[20];
int count[20];
printf("Please enter your string: ");
gets(pattern);
size = strlen(pattern);
for(i=0; i<size; i++)
if((i+1)%2 == 0)
vowel[i] = pattern[i];
else if((i+1)%2 != 0)
count[i] = pattern[i];
for(i=0; i<size/2; i++);
for(j=0; j<count[i]; j++)
printf("%s", vowel[i]);
}
I assumed you want to write the "invalid\n" string on stderr. If not just change the file descriptor given to write.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#define MAX_INPUT_SIZE 20
int
check_input(char *input)
{
while (*input)
{
if (*input < '0' || *input > '9')
{
write(2, "invalid\n", 8);
return 1;
}
while (*input >= '0' && *input <= '9')
input++;
if (*input < 'a' || *input > 'z')
{
write(2, "invalid\n", 8);
return 1;
}
input++;
}
return 0;
}
void
print_output(char *input)
{
int i;
while (*input)
{
i = atoi(input);
while (*input >= '0' && *input <= '9')
input++;
for (; i > 0; i--)
write(1, input, 1);
input++;
}
write(1, "\n", 1);
}
int
main()
{
char input[MAX_INPUT_SIZE];
do
{
printf("Please enter your string: ");
fgets(input, MAX_INPUT_SIZE, stdin);
input[strlen(input) - 1] = '\0';
}
while (check_input(input));
print_output(input);
return 0;
}
The steps are:
Read pattern
Check if pattern is valid
Generate output
Since the input length is not specified you have to assume a maximum length.
Another assumption is n is a single digit number.
Now you may read the whole expression with fgets() or read it char by char.
The latter allows you to check for validity as you read.
Lets use fgets() for convenience and in case the expression needs to be stored for later use.
char exp[100]; // assuming at most 50 instances of ([n][letter])
int len;
printf("Input: ");
fgets(exp, 100, stdin);
len = strlen(exp) - 1; // Discard newline at end
An empty input is invalid. Also a valid expression length should be even.
if (len == 0 || len%2 != 0) {
printf("Invalid-len\n");
return 1;
}
Now parse the expression and separately store numbers and letters in two arrays.
char nums[50], letters[50];
invalid = 0;
for (i = 0, j = 0; i < len; i += 2, j++) {
if (exp[i] >= '1' && exp[i] <= '9') {
nums[j] = exp[i] - '0';
} else {
invalid = 1;
break;
}
if (exp[i+1] >= 'a' && exp[i+1] <= 'z') {
letters[j] = exp[i+1];
} else {
invalid = 1;
break;
}
}
Notice that in each iteration if first char is not a number or second char is not a letter, then the expression is considered to be invalid.
If the expression is found to be invalid, nothing to do.
if (invalid) {
printf("Invalid\n");
return 1;
}
For a valid expression run nested loops to print the output.
The outer loop iterates for each ([n][letter]) pattern.
The inner loop prints n times the letter.
printf("Output: ");
for (i = 0; i < len/2; i++) {
for (j = 0; j < nums[i]; j++)
printf("%c", letters[i]);
}
This is a rather naive way to solve problems of this type. It is better to use regular expressions.
C standard library doesn't have regex support. However on Unix-like systems you can use POSIX regular expressions.
like this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#define prompt "Please enter your string: "
void occurs_error(const char *src, const char *curr){
printf("\nInvalid\n");
printf("%s\n", src);
while(src++ != curr){
putchar(' ');
}
printf("^\n");
}
bool invalid(char *pattern){
char *p = pattern;
while(*p){
if(!isdigit((unsigned char)*p)){//no number
occurs_error(pattern, p);
break;
}
strtoul(p, &p, 10);
if(!*p || !islower((unsigned char)*p)){//no character or not lowercase
occurs_error(pattern, p);
break;
}
++p;
}
return *p;
}
int main(void){
char pattern[20];
while(fputs(prompt, stdout), fflush(stdout), fgets(pattern, sizeof pattern, stdin)){
pattern[strcspn(pattern, "\n")] = 0;//chomp newline
char *p = pattern;
if(invalid(p)){
continue;
}
while(*p){
int n = strtoul(p, &p, 10);
while(n--)
putchar(*p);
++p;
}
puts("");
}
}

Performing arithmetic on Characters in C

I am trying to write a program that adds, subtracts, multiplies, and divides a string of characters. Where I'm at now with the program is figuring out how to split the input string into two strings, and then perform the appropriate +-/*.
The input should look like this abc+aaa
and the output for that should be abc + aaa = bcd
How do I convert character strings into integer strings?
#include <stdio.h>
#include <math.h>
#include <string.h>
int main() {
printf("This is a pseudo arithmetic program");
char input[10];
input[10] = '\0';
char first [9];
first[9] = '\0';
char last [9];
last[9] = '\0';
int i = 0;
int b;
int e;
while (input[0] != '0') {
if (input[0] == 0){
return -1;
}
printf("\nEnter a math problem in SOS format using only lowercase letters up to 9 characters");
printf("\nEx: abc+abc... type '0' to quit \n");
scanf("%s", input);
int x = 0;
x = strlen(input);
if (strchr(input, '+')){
for (i = 0; i <= x; i++) {
if (i == '+')
strncpy(first, &input[0], i-1);
i = 0;
}
for (i = x; i >= input[0]; i--) {
if (i == '+')
strncpy(last, &input[i], x);
i = 0;
}
printf("%s", first);
printf(" + ");
printf("%s", last);
printf(" = %d", first + last);
}
There seems to be multiple problems with your code:
There is a array out of bounds happening for almost all the arrays:
char input[10];
input[10] = '\0';
In this if you want to initialize the last character with '\0' then it should be
input [9] = '\0'
Arrays indexes always start from 0.
It is not clear what is the use of below lines:
while (input[0] != '0') { if (input[0] == 0){ return -1; }
When taking input for a string, why are prompting users to enter a 0 to end it?
strrchr returns the pointer from where the searched character begins. So, you can that itself to determine where the '+' symbol is and two split the strings instead of your while loop. See strrchr man page
Also, your idea of adding characters is not clear. From your example, it appears you are considering a = 1, b = 2 etc. In such a case, if your code is case insensitive, then you can convert all your input to upper case and then do (input[0] - 'A')+1 to convert your letters like a, b, c to 1, 2, 3 etc.
Hope these pointers help. Suggest you check your problem statement again and refactor your code accordingly.

Resources