Compare with string in if statement doesn't work - c

I try to compare my two strings that obtained from my scanf and fscanf. I already figured out what is the content inside the each variable. It both show the same strings, but after I compare with this two string in if statement, it doesn't work and execute else statement instead. What's wrong with my codes ?
int main(void)
{
...
char input[256];
printf("Enter your name: ");
scanf("%s",&input);
fp = fopen(_FILE,"r+");
for(i=0;i<textlines(_FILE);i++)
{
fscanf(fp,"%s %d",stuff[i].name,&stuff[i].salary);
if(input == stuff[i].name)
{
// Update name here
}
else
{
printf("Not Found");
}
}
return 0;
}

== just checks for pointer equality. Use strcmp instead

use the function strcmp in string.h library to compare your strings

As others have said, you need to use strcmp to compare strings (really character arrays). Also, you should not pass the address of name (i.e. &name) to the scanf() function.
You have this:
char input[256];
printf("Enter your name: ");
scanf("%s",&input);
....
if(input == stuff[i].name)
...
More correct code would include the following changes:
char input[256];
printf("Enter your name: ");
scanf("%s", input);
....
if (!strcmp(input, stuff[i].name))
....
You should check the definition and use of stuff[i].name as well. scanf() with a %s format character requires a simple char* parameter. The argument to strcmp() is const char* but using char* is fine and will be automatically promoted.
C is more flexible than other languages in that it allows you to obtain the address of variables. You create pointers to variables in this way. However, a variable declared as an array, such as input is already a pointer in a way. Only by providing an index to you dereference the pointer. Specifically:
char input[256];
input is a pointer to the storage of 256 char's
input can be thought of as a char* variable
input[0] is the first char in the array
input[1] is the second char in the array
input+1 is a pointer to the second char in the array.
input+0 (or simply input) is a pointer to the first char in the array.
&input is not good C form. You can kind of think of this as the address of the array but, in reality, input is already the address of the array. There is a use for such types of double-ly addressed variables but your case is not really one of them. Until you've had some practice with arrays and pointers (and their relationship) the following example might be a bit confusing but it does demonstrate where a char** variable might be used.
int allow_access_to_private_data(char ** data)
{
static char mystring[] = "This is a private string";
if (!data) return -1;
*data = mystring;
return 0;
}
int main(int argc, char* argv[])
{
char* string;
if (!allow_access_to_private_data(&string))
printf("Private data is: %s\n", string);
else
printf("Something went wrong!\n");
return 0;
}

Related

The below code runs encryption part well but when 'z' is entered it gives unexpected output and doesnt run decryption part

#include<stdio.h>
const char *encrypt(char *str);
const char *decrypt(char *str1);
int main()
{
char str[100],str1[100];
//Encryption
printf("Enter String for encryption\n");
gets(str);
encrypt(str);
printf("%s after encryption is %s\n",str,encrypt(str));
//Encryption
printf("Enter String for decryption\n");
gets(str1);
decrypt(str1);
printf("%s after decryption is %s",str1,decrypt(str1));
return 0;
}
const char *encrypt(char *str)
{
char en[100];
int i=0;
for(;i<100;i++)
{
en[i]=str[i]+1;
}
en[i]='\0';
return en;
}
const char *decrypt(char *str1)
{
char de[100];
int i=0;
for(;i<100;i++)
{
de[i]=str1[i]-3;
}
de[i]='\0';
return de;
}
You are returning a pointer to automatic variables en and de which are stored in the stack. This in turn means after returning from the functions encrypt and decrypt their place in the memory can be used by any other variable.
so to correct that, you need to define en and de as static.
const char *encrypt(char *str){
static char en[100];
int i=0;
for(;i<100;i++){
en[i]=str[i]+1;
}
en[i]='\0';
return en;
}
const char *decrypt(char *str1){
static char de[100];
int i=0;
for(;i<100;i++){
de[i]=str1[i]-3;
}
de[i]='\0';
return de;
}
Though a more suitable and safer way to implement that would be:
#include<stdio.h>
void encrypt(char *str, char *encStr);
void decrypt(char *str1, char* decStr);
int main()
{
char str[100], encDecStr[100];
//Encryption
printf("Enter String for encryption\n");
scanf("%s", str);
encrypt(str, encDecStr);
printf("%s after encryption is %s\n",str,encDecStr);
//Decryption
printf("Enter String for decryption\n");
scanf("%s", str);
decrypt(str, encDecStr);
printf("%s after decryption is %s",str,encDecStr);
return 0;
}
void encrypt(char *str, char *encStr)
{
for(char *c = str; *c != '\0'; c++)
{
*encStr++ = *c + 1;
}
*encStr='\0';
}
void decrypt(char *str1, char* decStr)
{
for(char *c = str1; *c != '\0'; c++)
{
*decStr++ = *c - 1;
}
*decStr++='\0';
}
Note: The code was not fully tested for different use cases.
There are quite a number of errors in your code:
Returning arrays with local storage duration:
The array's life time ends (i.e. it ceases to exist) as soon as you exit from the function, thus the pointer returned is dangling, reading from it is undefined behaviour
You write beyond the bounds of your local array: en[i] = '\0' with i being 100 after the loop is out of the range of valid indices from 0 to 99, which again is undefined behaviour.
You have differing offsets for encrypting (1) and decrypting (3).
Simply adding an offset without further checks (or modulo operations) will produce different character sets for input and output strings (might be your least problem...).
You always en-/decode the entire array, which is more than actually needed. Additionally the terminating null character then is encoded as well, resulting in different lengths of input and output and garbage at the end of encoded string.
Use of gets is dangerous as it allows a user to write beyond the input array, resulting in undefined behaviour. This is the reason why it actually has been removed from C language with C11 standard – which introduces a safe alternative gets_s. Yet another alternative (especially for pre-C11 code) is fgets.
For the dangling pointer problem there are several options:
Making the array static (as mentioned already):The disadvantage of this approach is that the function is not thread-safe any more. Additionally calling the function more than once overwrites previous results, if you haven't evaluated already or copied them they are lost.
Returning a dynamically allocated array, see malloc function. This comes with the risk of the caller forgetting to free the allocated memory again, which would result in a memory leak
Changing the input array in place: Disadvantage of is having to copy the input into a backup if it is yet needed afterwards.
Letting the caller provide the buffer.
Last option is most flexible and most idiomatic one, so I'll concentrate on this one:
void caesar(char const* input, char* output, int offset)
{
int const NumChars = 'z' - 'a';
offset = offset % NumChars + NumChars;
// ^ assures valid range, can still be negative
// ^ assures positive value, possibly
// out of range, but will be fixed later
for(;*input; ++input, ++output)
{
int c = *input - 'a';
// distance from character a
c = (c + offset) % NumChars;
// ^ fixes too large offset
*output = 'a' + c;
}
// as now iterating *until* null character found we now *need*
// to add it (in contrast to original version with whole array!)
*output = 0;
}
This variant includes an interesting idea: Let the caller define the offset to be applied! The modulo operation assures the valid range of the character, no matter how large the offset is. The great thing about: If a user encoded with some number n, exactly the same function can be used to decode again with -n (which is why I simply named it caesar according to the algorithm it implements). Note that this is untested code; if you find a bug please fix yourself...
Be aware, though, that this code still has two weaknesses:
It assumes ASCII encoding or compatible – at least one where letters a to z are in contiguous range, a is first character, z is last one. This is not true for all encodings, though, consider the (in-?)famous EBCDIC.
It assumes all input is in range of Latin minuscules only (from a - z), it does not consider white-space, digits, capital letters, punctuation marks... You might want to include special handling for all of these or at least the ones you might use.
You could fix these e.g. (many other variants are thinkable as well) by
converting all characters to either upper or lower case (toupper((unsigned char)*input) – assuming case doesn't matter)
search in an array of valid characters ("ABC...XYZ012...89") for the appropriate index and if found encode like above with NumChars being array length, otherwise (whitespace, punctuation) just leave as is.
In any case, the function would then be called like:
char input[128]; // prefer powers of 2 for array lengths...
char en[sizeof(input)];
char de[sizeof(input)];
gets_s(input, sizeof(input));
caesar(input, en, 7);
// en contains encrypted string, could e.g. be printed now
caesar(en, de, -7);
// de contains decrypted string
// you could even encode/decode in place:
caesar(input, input, 7);
// just be aware that this will fail, though, for the case if input
// and output overlap and input starts before output, as then at
// some point already encoded values will be read as input again:
// caesar(input, input + 1, 7) fails!!!
There's some issues in your code :
Not a very big issue for a beginner , but you should avoid gets function.
Because it doesn't check the input , it can cause buffers overflow and various security problems , try using fgets instead.
In encrypt , and decrypt functions , you are returning the address of an array located in the stack of the function , look :
const char *encrypt(char *str){
char en[100];
int i=0;
for(;i<100;i++){
en[i]=str[i]+1;
}
en[i]='\0';
return en;
}
Here , Since the en array is declared inside the function , after the return you may get garbage string when trying to read it.
The solution here , is to either malloc it , or declare a static array outside the function , and initialize it.
You are encrypting by adding 1 to the value of the string , and decrypt it by retrieving 3 . I don't know if this is what you intended to do.
Here's a new version of your code , try to check if it suits your need :
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
static char de[100] , en[100] ;
const char *decrypt(char *str1){
memset(de , 0 , 100) ;
int i=0;
for(;i<strlen(str1);i++){
de[i]=str1[i]-1;
}
de[i]='\0';
return (const char*) de;
}
const char* encrypt(char* str){
memset(en , 0 , 100) ;
int i=0;
for(;i<strlen(str);i++){
en[i]=str[i]+1;
}
en[i]='\0';
return (const char*) en;
}
int main(){
char str[100],str1[100];
//Encryption
printf("Enter String for encryption\n");
gets(str);
encrypt(str);
printf("%s after encryption is %s\n",str,encrypt(str));
//Encryption
printf("Enter String for decryption\n");
gets(str1);
decrypt(str1);
printf("%s after decryption is %s",str1,decrypt(str1));
return 0;
}
Your code does not handle a special case for the character 'z'. Thus
en[i]=str[i]+1;
Causes the character '{' to be written to the array en instead. For learning more about why this happens, I recommend you look at ASCII tables and looking at the integer values for alphabets.
Secondly, did you mean to type -3 in there?
de[i]=str1[i]-3;
This won't work if you're planning on using the decrypt() function to decrypt strings that you made using encrypt() because you're adding 1 to the character while encrypting and then subtracting a different number when decrypting, so the result will appear garbled.
I rewrote your code for you, since this is a beginner program, I made as little changes as possible so you can understand it. I WOULD HIGHLY RECOMMEND NOT USING gets() though... See here.
#include<stdio.h>
const char *encrypt(char *str);
const char *decrypt(char *str1);
int main()
{
char str[100],str1[100];
//Encryption
printf("Enter String for encryption\n");
gets(str); // DON'T USE GETS!!! USE fgets(str, 100, stdin);
encrypt(str);
printf("%s after encryption is %s\n", str, encrypt(str));
//Encryption
printf("Enter String for decryption\n");
gets(str1); // DON'T USE GETS!!! USE fgets(str, 100, stdin);
decrypt(str1);
printf("%s after decryption is %s", str1, decrypt(str1));
return 0;
}
const char *encrypt(char *str)
{
char en[100];
int i=0;
for(; i<100; i++)
{
if (str[i] == 'z')
{
en[i] = 'a';
continue;
}
en[i] = str[i] + 1;
}
en[i] = '\0';
return en;
}
const char *decrypt(char *str1)
{
char de[100];
int i=0;
for(; i<100; i++)
{
if (str[i] == 'a')
{
en[i] = 'z';
continue;
}
de[i] = str1[i] - 1;
}
de[i] = '\0';
return de;
}
Some criticisms
Like I said, gets() is really bad... See here for more details. Although it might be too complicated for you... A better alternative is fgets!
fgets(str, num, stdin)
takes user input from the console, and then stores it inside the array str, which must be large enough to store at least num characters. Don't worry about stdin if you don't know what that means. But be sure to always write it when using fgets as an alternative to gets
Like others have already posted, albeit using more technical jargon, it's a bad idea to declare an array inside a function and then return that array. You know the function ends when the return statement is hit, and at that point all the variables that were declared inside the function will get destroyed.
That doesn't necessarily mean that you can't read the data that was in them, but it becomes a probabilistic game where there's a teeny-tiny chance that the array will get corrupted after the function exits and before the data in that array is read. This is technically Undefined Behaviour.
I hope you know about pointers. You can modify the array which you passed as a parameter directly and then return that array, thus avoiding accessing an array outside it's lifetime.

Errors using pointers with Function in C

First of all I apologize, this is probably a simple question but I'm not very well versed in any coding. For this code, I need to use pointer syntax and define my own function to reverse a string. I'm not allowed to use strlen() in this situation. I've tried playing around with the pointers, but I always get the following errors:
incompatible type when assigning to type char[15] from type char
(I have to write this in pico, so I'm not exactly sure what line number it refers to. It appears to be somewhere around the point I call the strcmp() function
assignment makes integer from pointer without cast
(This one appears to be when I define the s pointer in the function or around there)
Any and all help/troubleshooting ideas would be much appreciated. I'm using a gcc compiler, if that matters
#include<stdio.h>
#include<string.h>
char revcheck(char String[15]);
int main(void)
{
char String[15];
printf("Enter a string: \n");
scanf(" %s", String);
if (strcmp(String, "ENGR-awesome"))
{
printf("That's Right!");
}
else
{
String = revcheck(String);
}
return 0;
}
char revcheck(char String[15])
{
char Letter, *end, *s;
end = strchr(String, '\0');
s = String;
while (end > s)
Letter = &end;
*end = *s;
*s = Letter;
end--;
s++;
return 0;
}
Your revcheck() returns a char. You are trying to assign that to a char[].
You should have your revcheck() return a char*:
char* revcheck(char String[15]);
First you should bear in mind that C-string is an array of chars, and can be represented as char*, a pointer to this array. So, revcheck should not return char. This is the string where the compiler gives the error:
String = revcheck(String);
revcheck can reverse the string in the String array itself (in place) without returning anything. (You can count the len yourself and then swap elements.)

How can I accept Char input in C?

So i try and compile I get a warning: comparison between pointer and integer [enabled by default] error, what am I doin wrong...?
int main(int argc, char *argv[])
{
char x;
printf("What would you like to do today?\n");
scanf("%s", &x);
if (x == "slm") {
printf("You SLAM a Faygo!");
} else if(x == "kik") {
printf("You KICK the Wicked Elixir!");
}
return 0;
}
Three problems:
You need to read into a string, not a char (with due consideration of buffer overflow), e.g.:
char x[128];
scanf ("%128s", x);
You can't compare strings with ==: you need to use strcmp:
#include <string.h>
...
if (0 == strcmp (x, "slm")) { ... }
You should check scanf's return code for success/failure:
if (1 != scanf (...)) {
perror ("scanf");
return EXIT_FAILURE;
}
(EXIT_FAILURE is defined in stdlib.h.)
x is a char. and "slm" is a string - a char *.
You might want to change that:
char *x;
But now you need to allocate memory. For example:
char *x = (char *)malloc(MAX_LENGTH*sizeof(char));
Also, fvu is right - use if(!strcmp(x,"slm")) instead of if(x ==slm) (strcmp return 0 when the strings are the same)
You're confusing char (which is single character) and char * (which is how C deals with strings)
You cannot meaningfully do == with char *'s the way you want to
You need to:
Change char x to either char *x or char x[1000];
If you use a char *, you will need to use malloc or similar to allocate space
for it
In either case, for production code, you will want to use
something that limits how much data can be read in (e.g. fgets, but
NOT gets).
You will want to use strcmp, which returns 0 if the two
strings are equal and non-zero if not.

Splitting a string with strtok() goes wrong

I'm trying to get input from the user while allocating it dynamically and then "split" it using strtok.
Main Questions:
Im getting an infinite loop of "a{\300_\377" and ",".
Why do i get a warning of "Implicitly declaring library function "malloc"/"realoc" with type void"
Other less important questions:
3.i want to break, if the input includes "-1", how do i check it? As you can see it breaks now if its 1.
4.In the getsWordsArray() i want to return a pointer to an array of strings. Since i dont know how many strings there are do i also need to dynamically allocate it like in the getInput(). (I dont know how many chars are there in each string)
int main(int argc, const char * argv[])
{
char input = getInput();
getWordsArray(&input);
}
char getInput()
{
char *data,*temp;
data=malloc(sizeof(char));
char c; /* c is the current character */
int i; /* i is the counter */
printf ("\n Enter chars and to finish push new line:\n");
for (i=0;;i++) {
c=getchar(); /* put input character into c */
if (c== '1') // need to find a way to change it to -1
break;
data[i]=c; /* put the character into the data array */
temp=realloc(data,(i+1)*sizeof(char)); /* give the pointer some memory */
if ( temp != NULL ) {
data=temp;
} else {
free(data);
printf("Error allocating memory!\n");
return 0 ;
}
}
printf("list is: %s\n",data); // for checking
return *data;
}
void getWordsArray(char *input)
{
char *token;
char *search = " ,";
token = strtok (input,search);
while (token != NULL ) {
printf("%s\n",token);
token = strtok(NULL,search);
}
}
EDIT:
i noticed i forgot to "strtok" command so i changed it to token = strtok(NULL,search);
I still get wierd output on the printf:
\327{\300_\377
Change:
int main(int argc, const char * argv[])
{
char input = getInput();
getWordsArray(&input);
}
to:
int main(int argc, const char * argv[])
{
char *input = getInput();
getWordsArray(input);
}
with a similar to the return value of getInput():
char *getInput()
{
// ...
return data;
}
In your code, you were only saving the first character of the input string, and then passing mostly garbage to getWordsArray().
For your malloc() question, man malloc starts with:
SYNOPSIS
#include <stdlib.h>
For your getchar() question, perhaps see I'm trying to understand getchar() != EOF, etc.
Joseph answered Q1.
Q2: malloc and realoc returns type void *. You need to explicitly convert that to char *. Try this:
data = (char *) malloc(sizeof(char));
Q3: 1 can be interpreted as one character. -1, while converting to characters, is equivalent to string "-1" which has character '-' and '1'. In order to check against -1, you need to use strcmp or strncmp to compare against the string "-1".
Q4: If you are going to return a different copy, yes, dynamically allocate memory is a good idea. Alternatively, you can put all pointers to each token into a data structure like a linked list for future reference. This way, you avoid making copies and just allow access to each token in the string.
Things that are wrong:
Strings in C are null-terminated. The %s argument to printf means "just keep printing characters until you hit a '\0'". Since you don't null-terminate data before printing it, printf is running off the end of data and just printing your heap (which happens to not contain any null bytes to stop it).
What headers did you #include? Missing <stdlib.h> is the most obvious reason for an implicit declaration of malloc.
getInput returns the first char of data by value. This is not what you want. (getWordsArray will never work. Also see 1.)
Suggestions:
Here's one idea for breaking on -1: if ((c == '1') && (data[i-1] == '-'))
To get an array of the strings you would indeed need a dynamic array of char *. You could either malloc a new string to copy each token that strtok returns, or just save each token directly as a pointer into input.

How do you pass a 2d array of strings to a function in C language?

I can't figure out how to pass radjectives (2D array of strings) to randomizeadj function.
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<ctype.h>
char randomizenouns(char[][]);
char randomizeadj(char[][]);
int main() // beginning of program.
{
int a=0, b=0;
char *answers[5]={'\0'};
char *rnouns[3][10]={'\0'};
char *radjectives[2][17]={'\0'};
char *rcolors[11]={'\0'};
radjectives[0][0]="intriguing";
// ...
radjectives[1][6]="loud";
rnouns[0][0]="puppies";
// ...
rnouns[1][9]="people";
rcolors[0]="black";
// ...
rcolors[10]="orange";
{ srand(time(NULL));
printf("\n\tProgram Paragrahs\n");
printf("\tFor this program you will answer several questions which will then be used to conjure a random story the length of a paragraph.Please Keep your answers clean.Enjoy\n");
printf("\nWhat is your name?");
scanf("%s\n",answers[0]);
printf("\nWhat is your favorite book?");
scanf("%s",answers[1]);
printf("\nWhat is your favorite color?");
scanf("%s",answers[2]);
printf("\nWhat city do you live in?");
scanf("%s",answers[3]);
printf("\nWhat car do you drive?");
scanf("%s",answers[4]);
Right here is where I get lost - I cannot figure out how to pass the radjectives array to the randomizeadj function.
printf("%s gets lost in their %s %s.\n",answers[0],randomizeadj(radjectives[a][b]),answers[1]);
printf("%s loves to play with %s %s.\n",answers[0],rcolors[(rand() %11)],randomizenouns(rnouns[a][b]);.
printf("%s lives in a(n) %s %s.\n",answers[0],randomizeadj(radjectives[a][b]),answers[3]);
printf("While living in %s %s drives a(n) %s %s.\n",answers[3],answers[0],rcolors[(rand() %11)],answers[4]);
printf("%s is a(n) %s person who likes the color %s.\n",answers[0],randomizeadj(radjectives[a][b]),answers[2]);
} // end of program
char randomizenouns(char nouns[x][y]);
{
int x=(rand() %3);
int y=(rand() %10);
char randomnoun= nouns[x][y];
return randomnoun;
}
char randomizeadj(char adjectives[x][y]);
{
int x=(rand() %2);
int y=(rand() %7);
char randomadjective= adjectives[x][y];
return randomadjective;
}
Simply
randomizeadj(radjectives);
e.g.
char *adj = randomizeadj(radjectives);
printf(adj);
At the moment things won't compile, change both the declarations and definitions of the functions to:
char *randomizenouns(char *nouns[3][10]);
char *randomizeadj(char *adjectives[2][17]);
or:
char *randomizenouns(char *nouns[][10]);
char *randomizeadj(char *adjectives[][17]);
Things I changed:
Changed char[][] (a 2D array of characters) to a 2D array or character pointers (also note that the first dimension of an array must always have a length specified).
Changed your functions to return char * rather than char (otherwise your function just returns a single character, rather than a string (but you still just return adjectives[x][y]).
Other things I changed:
Changed answers to not be an array of char pointers but rather a 2D array of chars, otherwise the compiler won't have memory assigned for the values you're trying to read in.
char answers[5][100];
There's also a ; where there shouldn't be here: (for both functions)
char randomizeadj(char adjectives[x][y]);
{
...
Test program.
you can simply pass it the way you have declared:
change your function definition and declaration to following:
char *randomizenouns(char *nouns[rows][cols])
char *randomizeadj(char *adjectives[rows][cols])
Note: for 2D array you need to pass cols size, so pass as required
EDIT
and in your code you have put semi-colon( ; ) in function defintion
char randomizeadj(char adjectives[x][y]); { ... }
char randomizenouns(char nouns[x][y]); { .... }
remove semi-colon from function definition
you were getting that incompatible pointer type error as earlier on you might not have changed the function declaration signatures with the matching function definition signatures.

Resources