Comparing strings with if else - c

I want to make a program that has a key to open. But when i comparing the key and the input, it always says "Wrong":
#include <stdio.h>
int main(){
char key[5]="april",ckey[5];
printf("Enter the key: ");
scanf("%s",ckey);
if(ckey==key){
printf("Correct.");
}
else{
printf("Wrong.");
}
return 0;
}
Is it possible to solve the problem without using other libraries?

You have to leave space before "%s" inside the scanf statement,so that the '\n character is not stored in ckey to ensure success of comparison.note: ckey must have size 6 or more.
#include <stdio.h>
#include <string.h>
int main(){
char key[] = "april",ckey[6];
printf("Enter the key: ");
scanf(" %5s",ckey);
if(!strcmp(ckey, key)){
printf("Correct.");
}
else{
printf("Wrong.");
}
return 0;
}

you have to check character by character.
try this code :
int main(){
int i = 0 ; int j = 1;
char key[6]="april",ckey[6];
printf("Enter the key: ");
scanf("%s",ckey);
for(i = 0; i < 6; i++){
if(ckey[i] != key[i])
j=0;
}
if(j == 1)
printf(%s,"Correct.");
else
printf(%s,"Wrong.");
return 0;
}

You make several mistakes in array sizing for your keys. Remember, a C string is always terminated by a nul character and you must account for this when you size your arrays to accept such strings.
scanf is unsafe, don't use it. Use fgets instead. A safe use of fgets is:
fgets (buffer, sizeof(buffer), stdin);
The answer to your question is no, it would be better to use strcmp if you want to lexically compare strings in C and that would involve including the header. But even so, this is not adding any other "libraries" since fgets and strcmp are in the same standard C library.
If you must not add any other headers (which makes no sense if this is part of a larger project but makes perfect sense if this is a homework problem) then you can write your own strcmp (we'll call it compare here) and call it from main.
#include <stdio.h>
int compare (const char* src, const char* dst)
{
int ret = 0;
while( ! (ret = *src - *dst) && *dst){
++src, ++dst;
}
if ( ret < 0 )
ret = -1 ;
else if ( ret > 0 )
ret = 1 ;
return( ret );
}
int main(void){
char key[6]="april",ckey[6];
printf("Enter the key: ");
fgets(ckey, sizeof ckey, stdin);
if(!compare(key,ckey)) {
printf("Correct.");
}
else {
printf("Wrong.");
}
return 0;
}
A better use of your time would be to write it using the functions available to you in the standard C library:
#include <stdio.h>
#include <string.h>
int main(void){
char key[6]="april",ckey[6];
printf("Enter the key: ");
fgets(ckey, sizeof ckey, stdin);
if(!strcmp(key,ckey)) {
printf("Correct.");
}
else {
printf("Wrong.");
}
return 0;
}
But even this solution has a flaw. It will accept "aprilaaaa" or any string beginning with "april" as a valid ckey. Can you explain why? How would you fix this?

In the condition of the if statement
if(ckey==key){
there are compared two addresses of the memory areas occupied by the arrays.
So you will always get false because the arrays occupy different memory areas.
If you may not use other standard functions as for example strncmp or memcmp declared in header <string.h> then you can write the following way
#include <stdio.h>
int main( void ){
char key[5]="april",ckey[6];
printf("Enter the key: ");
scanf("%5s",ckey);
size_t i = 0;
while ( i < sizeof( key ) && key[i] == ckey[i] ) ++i;
if( i == sizeof( key ) ){
printf("Correct.");
}
else{
printf("Wrong.");
}
return 0;
}
Instead of scanf it would be better to use fgets. In this case the size of the array ckey must be increased.
This declaration
char key[5]="april";
is totally valid in C though is not valid in C++.:)

Related

How to read word for word that are only separated by a ":" from the buffer?

I am making a language translator, and want to read from the buffer word by word and store them in a key-value struct.
The buffer contains such a file:
hola:hello
que:what
and so on. I already tried everything and I keep errors such as segmentation fault: 11 or just reading the same line again and again.
struct key_value{
char *key;
char *value;
};
...
struct key_value *kv = malloc(sizeof(struct key_value) * count);
char k[20]; //key
char v[20]; //value
int x = 0;
for(i = 0; i < numbytes; i++){
sscanf(buffer,"%21[^:]:%21[^\n]\n",k,v);
(kv + i)->key = k;
(kv + i)->value = v;
}
for(i = 0; i < count; i++){
printf("key: %s, value: %s\n",(kv + i)->key,(kv + i)->value);
}
free(buffer);
free(kv);
I expect the output to be key: hola, value: hello key: que, value: what,
but the actual output is just key: hola, value: hello again and again.
Which is the right way to do it?
There are multiple problems with your code, among them
On each loop iteration, you read from the beginning of the buffer. It is natural, then, that each iteration extracts the same key and value.
More generally, your read loop iteration variable seems to have no relationship with the data read. It appears to be a per-byte iteration, but you seem to want a per-line iteration. You might want to look into scanf's %n directive to help you track progress through the buffer.
You are scanning each key / value pair into the same local k and v variables, then you are assigning pointers to those variables to your structures. The resulting pointers are all the same, and they will become invalid when the function returns. I suggest giving structkey_value` arrays for its members instead of pointers, and copying the data into them.
Your sscanf format reads up to 21 characters each for key and value, but the provided destination arrays are not long enough for that. You need them to be dimensioned for at least 22 characters to hold 21 plus a string terminator.
Your sscanf() format and usage do not support recognition of malformed input, especially overlength keys or values. You need to check the return value, and you probably need to match the trailing newline with a %c field (the literal newline in the format does not mean what you think it means).
Tokenizing (the whole buffer) with strtok_r or strtok or even strchr instead of sscanf() might be easier for you.
Also, style note: your expressions of the form (kv + i)->key are valid, but it would be more idiomatic to write kv[i].key.
I've written a simple piece of code that may help you to solve your problem. I've used the function fgets to read from a file named "file.txt" and the function strchr to individuate the 1st occurence of the separator ':'.
Here the code:
#include <stdio.h>
#include <string.h>
#include <errno.h>
#define MAX_LINE_SIZE 256
#define MAX_DECODED_LINE 1024
struct decod {
char key[MAX_LINE_SIZE];
char value[MAX_DECODED_LINE];
};
static struct decod decod[1024];
int main(void)
{
FILE * fptr = NULL;
char fbuf[MAX_LINE_SIZE];
char * value;
int cnt=0,i;
if ( !(fptr=fopen("file.txt","r")) )
{
perror("");
return errno;
}
while( fgets(fbuf,MAX_LINE_SIZE,fptr)) {
// Eliminate UNIX/DOS line terminator
value=strrchr(fbuf,'\n');
if (value) *value=0;
value=strrchr(fbuf,'\r');
if (value) *value=0;
//Find first occurrence of the separator ':'
value=strchr(fbuf,':');
if (value) {
// Truncates fbuf string to first word
// and (++) points second word
*value++=0;
}
if (cnt<MAX_DECODED_LINE) {
strcpy(decod[cnt].key,fbuf);
if (value!=NULL) {
strcpy(decod[cnt].value,value);
} else {
decod[cnt].value[0]=0;
}
cnt++;
} else {
fprintf(stderr,
"Cannot read more than %d lines\n", MAX_DECODED_LINE);
break;
}
}
if (fptr)
fclose(fptr);
for(i=0;i<cnt;i++) {
printf("key:%s\tvalue:%s\n",decod[i].key,decod[i].value);
}
return 0;
}
This code reads all the lines (max 1024) that the file named file.txt contains, loads all individuated couples (max 1024) into the struct array decod and then printouts the content of the structure.
I wrote this code, I think it does the job! this is simpler than the accepted answer I think! and it uses just as much as memory is needed, no more.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct key_value{
char key[22];
char value[22];
};
void parse_str(char* str, struct key_value** kv_arr, int* num){
int n = 0;
int read = -1;
char k[22];
char v[22];
int current_pos = 0;
int consumed = 0;
/*counting number of key-value pairs*/
while (1){
if(current_pos > strlen(str)){
break;
}
read = sscanf(str + current_pos, "%21[^:]:%21[^\n]\n%n", k, v, &consumed);
current_pos += consumed;
if(read == 2){
++n;
}
}
printf("n = %d\n", n);
*kv_arr = malloc(sizeof(struct key_value) * n);
/*filling key_value array*/
int i = 0;
read = -1;
current_pos = 0;
consumed = 0;
while (1){
if(current_pos > strlen(str)){
break;
}
read = sscanf(str + current_pos, "%21[^:]:%21[^\n]\n%n", k, v, &consumed);
current_pos += consumed;
if(read == 2){
struct key_value* kv = &((*kv_arr)[i]);
strncpy(kv->key, k, 22);
strncpy(kv->value, v, 22);
++i;
}
}
*num = n;
}
int main(){
char* str = "hola:hello\n"
"que:what\n";
int n;
struct key_value* kv_arr;
parse_str(str, &kv_arr, &n);
for (int i = 0; i < n; ++i) {
printf("%s <---> %s\n", kv_arr[i].key, kv_arr[i].value);
}
free(kv_arr);
return 0;
}
output :
n = 2
hola <---> hello
que <---> what
Process finished with exit code 0
Note: sscanf operates on a const char*, not an input stream from a file, so it will NOT store any information about what it has consumed.
solution : I used %n in the format string to get the number of characters that it has consumed so far (C89 standard).

Segmentation fault caused by fgets() in C

This is a problem I don't understand - I am using fgets() in main and it works. I use it (I think) in exactly the same way in a function and I get an error [Segmentation fault core dumped -- exit code 139).
This code is based on a sample program in book Ivor Horton's "Beginning C" (it's a old tile but I'm just wanting to learn the basics from it).
My program is as follows. I am working on *nix using Geany (basically, compiling with GCC). You can see that fgets works in main (output is the string you enter). But it doesn't work in the function str_in(). It gets as far as the second printf() statement to enter a string, no further. Note that in the book, Horton uses gets(). I am trying to implement a safer string input function here, but no joy.
By the way the program is supposed to sort strings stored in an array of string pointers.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TRUE 1
#define FALSE 0
#define MAX_NUM_STRINGS 50
int str_in(char **); /*Pointer to a string pointer*/
void str_sort(char *[], int n); /*Array of pointers to strings, number of strings in array*/
void str_out (char *[], int n); /*Array of pointers to strings, number of strings in array*/
int main(){
char *pS[MAX_NUM_STRINGS] = { NULL }; /*Array of pointers to strings stored in str_space*/
int numStrings = 0; /*Count of strings*/
char buffer[BUFSIZ];
printf("Enter a string\n");
fgets(buffer, BUFSIZ, stdin);
printf("%s", buffer);
printf("fgets works here\n\n");
/* get string input from user - a pointer to each string is saved in pS */
while ( str_in(&pS[numStrings]) && numStrings < MAX_NUM_STRINGS)
numStrings++;
if ( numStrings > 0 ){
str_sort(pS, numStrings);
str_out(pS, numStrings);
}
return 0;
}
int str_in(char** pString){
char buffer[BUFSIZ];
char *p;
printf ("Enter string:\n");
fgets(buffer, 60, stdin);
printf("fgets doesn't work here!!\n");
if( buffer != NULL ){
printf("here");
if ((p = strchr(buffer, '\n')) != NULL)
*p = '\0'; /*replace newline with null character*/
else
return FALSE;
if ( strlen(buffer) > 0 ){
strcpy(*pString, buffer);
return TRUE;
}
else
return FALSE; /*blank line - end of input*/
}
else
return FALSE;
}
void str_sort(char* pStrings[], int n){
/*sort strings by manipulating array of string pointers*/
char *temp;
int sorted = FALSE;
int i = 0;
while (!sorted){
sorted = TRUE;
for(i = 0; i < n - 1; i++){
temp = pStrings[i];
if ( strcmp(temp, pStrings[i+1]) > 1 ){
pStrings[i] = pStrings[i+1];
pStrings[i+1] = temp;
sorted = FALSE;
break;
}
}
}
}
void str_out(char* pStrings[], int n){
/*print strings to standard output. Free memory as each string is printed */
int i = 0;
printf("Sorted strings:\n");
for(i = 0; i < n; i++){
printf("%s", pStrings[i]);
free(pStrings[i]);
}
}
The segmentation fault is not caused by fgets(), but by strcpy():
strcpy(*pString, buffer);
You try to write to *pString, but you never allocate memory for it. pS in main() is just an array of null pointers.
Another thing is with the test with if( buffer != NULL ), that would never be true since buffer is an array, not a pointer.
You must check for the return value of fgets to see if you have successfully received something, if not then you should never use your buffer as a string as you are not NUL terminating the buffer.
/* Checking for buffer != NULL is of no use */
/* as buffer will always be not NULL since */
/* since you have allocated it as char buffer[BUFSIZ] */
if (fgets(buffer, BUFSIZ, stdin) == NULL) {
/* buffer may not be a valid string */
}
So what you can do it to initialize the buffer to a NUL string, as soon as you enter the function (after your declarations are done
buffer[0] = 0; /* initialize to NUL string */
now you can use buffer as a string anywhere.
Also note than if BUFSIZ is too big greater than a couple of KB, then your might get seg fault due to stack overflow. If they are too big you could make buffer as "static char" instead of "char".

Processing outputs of multiple inputs in C

It's not something trivial but I would like to know the best way to process multiple outputs, for example:
Input
First line of input will contain a number T = number of test cases. Following lines will contain a string each.
Output
For each string, print on a single line, "UNIQUE" - if the characters are all unique, else print "NOT UNIQUE"
Sample Input
3
DELHI
london
#include<iostream>
Sample Output
UNIQUE
NOT UNIQUE
NOT UNIQUE
So how can I accomplish outputs like that? My code so far is:
int main(int argc, char *argv[])
{
int inputs, count=0;
char str[100];
char *ptr;
scanf("%d",&inputs);
while(inputs-- >0)
{
scanf("%s",str);
for(ptr=str; *ptr!='\0';ptr++)
{
if( *ptr== *(ptr+1))
{
count++;
}
}
if(count>0)
{
printf("NOT UNIQUE");
}
else
{
printf("UNIQUE");
}
}
}
But the above will obviously print the output after each input, but I want the output only after entering all the inputs, if the user enters 3, then the user have to give 3 strings and after the output will be given whether the given strings are unique or not. So I want to know how can I achieve the result given in the problem. Also another thing I want to know is, I am using an array of 100 char, which it can hold a string up to 100 characters, but what do I have to do if I want to handle string with no limit? Just declaring char *str is no good, so what to do?
Hope this helps:
#include <stdio.h>
int main(int argc, char *argv[])
{
int inputs,count=0;
char str[20];
scanf("%d",&inputs);
char *ptr;
char *dummy;
while(inputs-- >0)
{
scanf("%s",str);
for(ptr=str; *ptr!='\0';ptr++)
{
for(dummy=ptr+1; *dummy != '\0';dummy++)
{
if( *ptr== *dummy)
{
count=1;
}
}
if(count == 1)
break;
}
if(count>0)
{
printf("NOT UNIQUE");
}
else
{
printf("UNIQUE");
}
}
}
If you want to save stuff for later use, you must store it somewhere. The example below stores up to 10 lines in buf and then points str to the current line:
#include <stdlib.h>
#include <stdio.h>
#include <string.h> /* for strlen */
#include <ctype.h> /* for isspace */
int main(int argc, char *argv[])
{
int ninput = 0;
char buf[10][100]; /* storage for 10 strings */
char *str; /* pointer to current string */
int i;
printf("Enter up to 10 strings, blank to and input:\n");
for (i = 0; i < 10; i++) {
int l;
str = buf[i];
/* read line and break on end-of-file (^D) */
if (fgets(str, 100, stdin) == NULL) break;
/* delete trailing newline & spaces */
l = strlen(str);
while (l > 0 && isspace(str[l - 1])) l--;
str[l] = '\0';
/* break loop on empty input */
if (l == 0) break;
ninput++;
}
printf("Your input:\n");
for (i = 0; i < ninput; i++) {
str = buf[i];
printf("[%d] '%s'\n", i + 1, str);
}
return 0;
}
Note the two separate loops for input and output.
I've also rejiggled your input. I'm not very fond of fscanf; I prefer to read input line-wise with fgets and then analyse the line with strtok or sscanf. The advantage over fscanf is that yout strings may contain white-space. The drawback is that you have a newline at the end which you usually don't want and have to "chomp".
If you want to allow for longer strings, you should use dynamic allocation with malloc, although I'm not sure if it is useful when reading user input from the console. Tackle that when you have understood the basics of fixed-size allocation on the stack.
Other people have already pointed you to the error in your check for uniqueness.

How to verify a password to have at least one uppercase, lowercase and number in C?

What should i do to make it keep looping until it have at least one uppercase, lowercase and number ?
I'm stuck, really stuck...
char password[100][15];
i=1;
printf("Password [3..10]: ");
gets(password[i]);
while (strlen(password[i])>10 || strlen(password[i])<3 || ) {
do{
printf(" Password must contain at least 1 uppercase, 1 lowercase, and 1 number\nPassword [3..10]: ");
gets(password[i]);
} while (strlen(password[i])>10 || strlen(password[i])<3 );
This should work:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int is_legal(char *p) {
int number = 0, lower = 0, upper = 0, length = 0;
for( ; *p; p++) {
number += isdigit(*p);
lower += islower(*p);
upper += isupper(*p);
length++;
}
return number > 0 && lower > 0 && upper > 0 && length > 3 && length < 10;
}
char *my_gets(char *buf, int bufsize, FILE *file) {
if(fgets(buf, bufsize, file) == 0) {
return 0;
}
int n = strlen(buf);
if(buf[n-1] == '\n') buf[n-1] = 0;
return buf;
}
int get_password(char *buf, int bufsize, FILE *file) {
printf("Password [3..10]: ");
if(my_gets(buf, bufsize, file) == 0) {
return -1;
}
while(is_legal(buf) == 0) {
printf(" Password must contain at least 1 uppercase, 1 lowercase, and 1 umber\nPassword [3..10]: ");
if(my_gets(buf, bufsize, file) == 0) {
return -1;
}
}
return 0;
}
int main(void) {
char password[100][15];
int i = 0;
if(get_password(password[i], sizeof(password[i]), stdin) != 0) {
fprintf(stderr, "Error getting password\n");
exit(1);
}
return 0;
}
Use this regular expression:
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$
It says that you must have at least one lowercase character, one uppercase character and at least one number PLUS it is less typing than the ctype method.
Example:
#include <regex.h>
int main (int argc, char *argv[])
{
regex_t regex;
int regexResult = regcomp(&regex, "^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$", 0);
regexResult = regexec(&regex, passwordVariableHere, 0, NULL, 0);
if (!regex)
{
// Match
}
}
Look at ctype.h header. Examine every character of password until all conditions (upper, lower, digit) are met. If you reach end of password string and any of conditions are unsatisfied, password is wrong.
Maybe it's an easy way to check the characters position in the ASCII table. You can check all characters as numbers between 65 and 90 for uppsercase characters and the same for lowercase.
For a number you could use atoi() function from standard c library.
Or another possibility is using functions from ctype.h: islower(), isupper() or isdigit().
I don't get very well why you are using an array of 15-chars long passwords, but I suppose your criteria refers to just one of those password and not to the others: you want to check that a password has requirements to be considered a "good" password; this is my understanding. Then...
The function gets is rather unsafe. Avoid using it.
The idea is to ask for a password, check it and loop if it does not fit your criteria. There's not a single way to do it of course.
// include files for I/O funcs
#include <stdio.h>
for(;;)
{
printf("insert pwd: ");
gets(buffer); // argh I've said: don't use this
if ( !pass_criteria(buffer) ) {
printf("criteria are ....\n");
} else break;
}
Then pass_criteria could be something like
// include files for strlen and is* funcs
#include <ctype.h>
#include <string.h>
int pass_criteria(const char *buf)
{
int upcount, lowcount, numcount;
if (strlen(buf) < minimum_pass_len ||
strlen(buf) > max_pass_len) return 0; // 0 being false
for (int i = 0; i < strlen(buf); ++i) {
if (isdigit(buf[i]) numcount++;
if (isupper(buf[i]) upcount++;
if (islower(buf[i]) lowcount++;
}
return numcount > 0 && upcount > 0 && lowcount > 0;
}
It's easy to change criteria, e.g. if you want at least 2 number (digit), put numcount > 1 and so on.
Instead of gets
Gets is dangerous for buffer overflow. Try using e.g. fgets like this:
fgets(buffer, buffer_size, stdin);
where buffer_size is the size of your buffer (15 in your case, but avoid using a literal constant; prefer a proper #define or use sizeof, e.g. sizeof (password[0]). Note also that fgets does not discard final newline.

read string of character and assign it to an array

I don't know how to work with scanf and get the input of it for the entry of the function readBigNum I want to make array until the user entered the Enter and also I want to write a function for assigning it into an array and return the size of the large number
I want readBigNum to exactly have the char *n but I can not relate it in my function
#include <stdio.h>
int readBigNum(char *n)
{
char msg[100],ch;
int i=0;
while((ch=getchar())!='\n')
{
if(ch!='0'||ch!='1'||ch!='2'||ch!='3'||ch!='4'||ch!='5'||ch!='6'||ch!='7'||ch!='8'||ch!='9')
return -1;
msg[i++]=ch;
}
msg[i]='\0';
i=0;
return i;
}
int main()
{
const char x;
const char n;
n=scanf("%d",x);
int h=readBigNum(&n);
printf(h);
}
If I understand your question correctly, you want to implement a function that will read numbers from stdin storing them in a buffer. If a non-number is encountered, you want to return -1. If a new-line is encountered, you want to return the number of characters that were read. If that's correct, you'll probably want your code to look something like the following:
#include <stdio.h>
int readBigNum(char* n)
{
char ch;
int i=0;
while ((ch = getchar()) != '\n') {
if (ch < '0' || ch > '9') {
return -1;
}
n[i++] = ch;
}
n[i] = '\0';
return i;
}
int main(void) {
char buf[100];
int bytes = readBigNum(buf);
printf("%s\n", buf);
printf("%d\n", bytes);
};
The main differences from your implementation
The array to be populated is initialized in main and passed to the readBigNum function. This is a little simpler than having the function control the memory, in which case you would need likely need to deal with malloc and free. Even with this, you run the risk of a buffer overrun and will likely want to take additional precautions to prevent that.
The function does not set i to 0 before returning it. The original code could never return a value other than -1 (on error) or 0, which didn't appear to be the intent.
This code doesn't use scanf. Given your description of what you wanted to accomplish, using scanf didn't appear to be a good fit, however if you provide more information on why you were calling it might help to inform this answer.
The printf call was incorrect, it has been updated to print the number of bytes returned, and an additional printf call was added to print the updated buffer.
Remember that getchar() returns type int, not char. This is because the function may return EOF (which is defined as a negative integer with no particular value).
Also, for functions that deal with buffers, it is always a good idea to take an extra argument that describes the size of the array. This helps reduce buffer overruns because you know how far you can go. With your existing function, if the user types more than 100 characters, your buffer is overrun.
#include <stdio.h>
#include <ctype.h>
int readBigNum(char *n, size_t len)
{
int ch;
int i = 0;
// we make sure 'i' is less than 'len - 1' to leave space for '\0'
while((ch = getchar()) != EOF && i < (len - 1))
{
if (ch == '\n') // stop on linefeed
break;
else if (!isdigit(ch))) // abort on invalid character
return -1;
else
n[i++] = (char) ch;
}
msg[i] = '\0';
return i;
}
int main(void)
{
char buf[100];
int result = readBigNum(buf, sizeof buf);
if (result > 0)
printf("Length %d : %s\n", result, buf);
else
printf("Invalid number!\n");
}

Resources