This question already has answers here:
strcmp on a line read with fgets
(6 answers)
Closed 7 years ago.
For unknown reason, result of running my C program is quite unexpected. I think that it has to be some kind of a beginner mistake, however I can't find out really, where is it.
#include <stdio.h>
#include <string.h>
int main()
{
char string1[50];
char string2[50];
int compare;
puts("Enter two strings: ");
fgets(string1, strlen(string1)+1, stdin);
fgets(string2, strlen(string2)+1, stdin);
compare=strcmp(string1, string2); /* usage of extra variable makes the code more readable but wastes more memory */
printf("%d: ",compare);
if (compare<0) puts("First string is lesser");
else if (compare>0) puts ("First string is bigger");
else puts("Strings are equal");
return 0;
}
And on testing:
Enter two strings:
heheisntthisalongstring
heheisntthisalongstring
1: First string is bigger
------------------
(program exited with code: 0)
Press return to continue
Shouldn't those strings be equal?
fgets(string1, strlen(string1)+1, stdin);
fgets(string2, strlen(string2)+1, stdin);
These are wrong. string1 and string2 are not initialized, and strlen just counts the number of bytes, till hitting \0. In this case, strlen could return any (random non-negative) number.
Use sizeof, instead of strlen here.
Here
char string1[50];
char string2[50];
you dont initialise them, so your initial calls to strlen are unreliable as they are looking for the first null char they find after the start of the array. This could be anywhere and the results of the call may or may not be a true reflection on the size - you just cant rely at all on the results.
string1 is not memset to 0, So strlen(string1) value will not give the expected value (50). strlen will counts the character till it reaches \0. So it may leads to crash also(an undefined behaviour).
Better memset both string1 and string2 like below.
char string1[50] = {0};
char string2[50] = {0};
and also use sizeof operator to get the value 50.
fgets(string1, sizeof(string1), stdin);
fgets(string2, sizeof(string2), stdin);
or else directly go for scanf
scanf("%s", string1);
scanf("%s", string2);
Here have a look at this-strlen
Although the code you are using is not good but you can still get your expected answer by using strncmp giving the 3rd parameter the strlen of a common string variable. Just for fun.
Always initialize your variables or they can lead your application to crash. You can see the examples here- strncmp
Related
This question already has answers here:
How do I properly compare strings in C?
(10 answers)
Closed 5 years ago.
char str[6];
do
{
printf("Enter the string you wanna check:");
scanf("%s", str);
}
while(str != "exit");
Why does this not work?
str will never equal "exit", because you're comparing the addresses of two different sections of memory. You probably want to compare the contents of the strings, for which there is a function strcmp().
"exit" is a char[5] generated by the compiler at some address in the data segment. This address is definitely different from the address of str, as two different objects cannot occupy the same location in memory.
The != operator between expressions of type char[] compares two pointers. These two pointers are the address of "exit" and the address of str, which, as I have already explained, will never be equal.
So, the expression str != "exit" will never evaluate to true. Which brings us to another point: your compiler should have issued a warning about this condition being always false. Which means that you are trying to program without -Wall. Don't do this, you are never going to get very far. Always use the highest warning level, and when you see warnings, always fix them.
To correct the problem, do as user3121023 suggested in a comment, and use strcmp() to compare strings.
The short answer is: it does not work because you must use strcmp(str, "exit") to compare the strings and loop for as long as the return value of strcmp() is not 0.
The long answer is: there are more problems in this little code fragment:
The array into which you read a word is very short and you do not limit the number of characters scanf() is likely to store there. Any user input longer than 5 non space characters will cause undefined behavior.
You do not check the return value of scanf(). A premature end of file, such as redirecting input from an empty file, will cause an infinite loop.
Here is how the code can be written in a safer way:
#include <stdio.h>
int main(void) {
char str[80];
for (;;) {
printf("Enter the string you wanna check:");
if (scanf("%79s", str) != 1 || strcmp(str, "exit") == 0)
break;
}
return 0;
}
As suggested above, use strcmp from the <string.h> header file.
char str[6];
do {
printf("Enter the string you wanna check:");
scanf("%s", str);
} while(!strcmp(str, "exit"));
Try :
#include <stdio.h>
#include <string.h>
int main() {
char str[6];
do
{
printf("Enter the string you wanna check:");
scanf("%s", str);
}
while(strcmp(str, "exit") != 0);
return 0;
}
Anyone know how to copy to strings? Cause I used the function strcpy but when I print the result it show strange characters. I want to concatenate 'name' + '#' + 'e-mail'. With scanf I have to put the character null '\0'?
#include <stdio.h>
#include <string.h>
int main (){
char message[150];
char name[150];
char mail[150];
char result[150];
printf("Introduce name: \n");
scanf("%s",message);
printf("Introduce email \n");
scanf("%s",server);
strcpy(result,message);
result[strlen(result)]='#';
strcpy(&result[strlen(result)],server);
printf("RESULT: %s\n",result);
return 0;
}
result[strlen(result)]='#'; overwrites the NUL terminator introduced into result by strcpy(result,message);. So the result of a subsequent strlen is undefined.
A better solution is to use strncat, or you could get away with writing
char result[150] = {'\0'};
which will initialise the entire array.
But you still run the risk of overflowing your result array. You could use the safer strncpy to obviate that. Better still, use snprintf and have the C standard library perform the concatenation for you.
I am currently learning C, and so I wanted to make a program that asks the user to input a string and to output the number of characters that were entered, the code compiles fine, when I enter just 1 character it does fine, but when I enter 2 or more characters, no matter what number of character I enter, it will always say there is just one character and crashes after that. This is my code and I can't figure out what is wrong.
int main(void)
{
int siz;
char i[] = "";
printf("Enter a string.\n");
scanf("%s", i);
siz = sizeof(i)/sizeof(char);
printf("%d", siz);
getch();
return 0;
}
I am currently learning to program, so if there is a way to do it using the same scanf() function I will appreciate that since I haven't learned how to use any other function and probably won't understand how it works.
Please, FORGET that scanf exists. The problem you are running into, whilst caused mostly by your understandable inexperience, will continue to BITE you even when you have experience - until you stop.
Here is why:
scanf will read the input, and put the result in the char buffer you provided. However, it will make no check to make sure there is enough space. If it needs more space than you provided, it will overwrite other memory locations - often with disastrous consequences.
A safer method uses fgets - this is a function that does broadly the same thing as scanf, but it will only read in as many characters as you created space for (or: as you say you created space for).
Other observation: sizeof can only evaluate the size known at compile time : the number of bytes taken by a primitive type (int, double, etc) or size of a fixed array (like int i[100];). It cannot be used to determine the size during the program (if the "size" is a thing that changes).
Your program would look like this:
#include <stdio.h>
#include <string.h>
#define BUFLEN 100 // your buffer length
int main(void) // <<< for correctness, include 'void'
{
int siz;
char i[BUFLEN]; // <<< now you have space for a 99 character string plus the '\0'
printf("Enter a string.\n");
fgets(i, BUFLEN, stdin); // read the input, copy the first BUFLEN characters to i
siz = sizeof(i)/sizeof(char); // it turns out that this will give you the answer BUFLEN
// probably not what you wanted. 'sizeof' gives size of array in
// this case, not size of string
// also not
siz = strlen(i) - 1; // strlen is a function that is declared in string.h
// it produces the string length
// subtract 1 if you don't want to count \n
printf("The string length is %d\n", siz); // don't just print the number, say what it is
// and end with a newline: \n
printf("hit <return> to exit program\n"); // tell user what to do next!
getc(stdin);
return 0;
}
I hope this helps.
update you asked the reasonable follow-up question: "how do I know the string was too long".
See this code snippet for inspiration:
#include <stdio.h>
#include <string.h>
#define N 50
int main(void) {
char a[N];
char *b;
printf("enter a string:\n");
b = fgets(a, N, stdin);
if(b == NULL) {
printf("an error occurred reading input!\n"); // can't think how this would happen...
return 0;
}
if (strlen(a) == N-1 && a[N-2] != '\n') { // used all space, didn't get to end of line
printf("string is too long!\n");
}
else {
printf("The string is %s which is %d characters long\n", a, strlen(a)-1); // all went according to plan
}
}
Remember that when you have space for N characters, the last character (at location N-1) must be a '\0' and since fgets includes the '\n' the largest string you can input is really N-2 characters long.
This line:
char i[] = "";
is equivalent to:
char i[1] = {'\0'};
The array i has only one element, the program crashes because of buffer overflow.
I suggest you using fgets() to replace scanf() like this:
#include <stdio.h>
#define MAX_LEN 1024
int main(void)
{
char line[MAX_LEN];
if (fgets(line, sizeof(line), stdin) != NULL)
printf("%zu\n", strlen(line) - 1);
return 0;
}
The length is decremented by 1 because fgets() would store the new line character at the end.
The problem is here:
char i[] = "";
You are essentially creating a char array with a size of 1 due to setting it equal to "";
Instead, use a buffer with a larger size:
char i[128]; /* You can also malloc space if you desire. */
scanf("%s", i);
See the link below to a similar question if you want to include spaces in your input string. There is also some good input there regarding scanf alternatives.
How do you allow spaces to be entered using scanf?
That's because char i[] = ""; is actually an one element array.
Strings in C are stored as the text which ends with \0 (char of value 0). You should use bigger buffer as others said, for example:
char i[100];
scanf("%s", i);
Then, when calculating length of this string you need to search for the \0 char.
int length = 0;
while (i[length] != '\0')
{
length++;
}
After running this code length contains length of the specified input.
You need to allocate space where it will put the input data. In your program, you can allocate space like:
char i[] = " ";
Which will be ok. But, using malloc is better. Check out the man pages.
This is a very fun problem I am running into. I did a lot of searching on stack overflow and found others had some similar problems. So I wrote my code accordingly. I originally had fscan() and strcmp(), but that completely bombed on me. So other posts suggested fgets() and strncmp() and using the length to compare them.
I tried to debug what I was doing by printing out the size of my two strings. I thought, maybe they have /n floating in there or something and messing it up (another post talked about that, but I don't think that is happening here). So if the size is the same, the limit for strncmp() should be the same. Right? Just to make sure they are supposedly being compared right. Now, I know that if the strings are the same, it returns 0 otherwise a negative with strncmp(). But it's not working.
Here is the output I am getting:
perk
repk
Enter your guess: perk
Word size: 8 and Guess size: 8
Your guess is wrong
Enter your guess:
Here is my code:
void guess(char *word, char *jumbleWord)
{
size_t wordLen = strlen(word);
size_t guessLen;
printf("word is: %s\n",word);
printf("jumble is: %s\n", jumbleWord);
char *guess = malloc(sizeof(char) * (MAX_WORD_LENGTH + 1));
do
{
printf("Enter your guess: ");
fgets(guess, MAX_WORD_LENGTH, stdin);
printf("\nword: -%s- and guess: -%s-", word, guess);
guessLen = strlen(guess);
//int size1 = strlen(word);
//int size2 = strlen(guess);
//printf("Word size: %d and Guess size: %d\n",size1,size2);
if(strncmp(guess,word,wordLen) == 0)
{
printf("Your guess is correct\n");
break;
}
}while(1);
}
I updated it from suggestions below. Especially after learning the difference between char * as a pointer and referring to something as a string. However, it's still giving me the same error.
Please note that MAX_WORD_LENGTH is a define statement used at the top of my program as
#define MAX_WORD_LENGTH 25
Use strlen, not sizeof. Also, you shouldn't use strncmp here, if your guess is a prefix of the word it will mistakenly report a match. Use strcmp.
sizeof(guess) is returning the size of a char * not the length of the string guess. Your problem is that you're using sizeof to manage string lengths. C has a function for string length: strlen.
sizeof is used to determine the size of data types and arrays. sizeof only works for strings in one very specific case - I won't go into that here - but even then, always use strlen to work with string lengths.
You'll want to decide how many characters you'll allow for your words. This is a property of your game, i.e. words in the game are never more that 11 characters long.
So:
// define this somewhere, a header, or near top of your file
#define MAX_WORD_LENGTH 11
// ...
size_t wordlen = strlen(word);
size_t guessLen;
// MAX_WORD_LENGTH + 1, 1 more for the null-terminator:
char *guess = malloc(sizeof(char) * (MAX_WORD_LENGTH + 1));
printf("Enter your guess: ");
fgets(guess, MAX_WORD_LENGTH, stdin);
guessLen = strlen(guess);
Also review the docs for fgets and note that the newline character is retained in the input, so you'll need to account for that if you want to compare the two words. One quick fix for this is to only compare up to the length of word, and not the length of guess, so: if( strncmp(guess, word, wordLen) == 0). The problem with this quick fix is that it will pass invalid inputs, i.e. if word is eject, and guess is ejection, the comparison will pass.
Finally, there's no reason to allocate memory for a new guess in each iteration of the loop, just use the string that you've already allocated. You could change your function setup to:
char guess(char *word, char *jumbledWord)
{
int exit;
size_t wordLen = strlen(word);
size_t guessLen;
char *guess = malloc(sizeof(char) * (MAX_WORD_LENGTH + 1));
do
{
printf("Enter your guess: ");
// ...
As everyone else has stated, use strlen not sizeof. The reason this is happening though, is a fundamental concept of C that is different from Java.
Java does not give you access to pointers. Not only does C have pointers, but they are fundamental to the design of the language. If you don't understand and use pointers properly in C then things won't make sense, and you will have quite a bit of trouble.
So, in this case, sizeof is returning the size of the char * pointer, which is (usually) 4 or 8 bytes. What you want is the length of the data structure "at the other end" of the pointer. This is what strlen encapsulates for you.
If you didn't have strlen, you would need to dereference the pointer, then walk the string until you find the null byte marking the end.
i = 1;
while(*guess++) { i++ }
Afterwards, i will hold the length of your string.
Update:
Your code is fine, except for one minor detail. The docs for fgets note that it will keep the trailing newline char.
To fix this, add the following code in between the fgets and strncmp sections:
if ( guess[guessLen-1] == '\n' ) {
guess[guessLen-1] = '\0';
}
That way the trailing newline, if any, gets removed and you are no longer off by one.
Some list of problems / advices for your code, much too long to fit in a comment:
your function returns a char which is strange. I don't see the
logic and what is more important, you actually never return a value. Don't do that, it will bring you trouble
look into other control structures in C, in particular don't do your exit thing. First, exit in C is a function, which does what it says, it exits the program. Then there is a break statement to leave a loop.
A common idiom is
do {
if (something) break;
} while(1)
you allocate a buffer in each iteration, but you never free it. this will give you big memory leaks, buffers that will be wasted and inaccessible to your code
your strncmp approach is only correct if the strings have the same length, so you'd have to test that first
Can anyone tell me why this code crashes? It's simple, if the length of the string is > than 16, ask again for a string. It works if I write control = 1 inside the if statement, but it should work the same without it, 'cause the value of control at that point is 1, am I right?
thans (I'm learning)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(void)
{
int control = 1;
char word[16] ;
printf("Enter a word: ");
while(control == 1)
{
scanf("%s", word);
int len = strlen(word);
printf("Lenght is: %d\n", len);
if (len >= 16)
{
printf("Word lenght to long, enter a new one: ");
}
else
{
control = 0;
}
}
printf("This is the word: %s\n", word );
}
char word[16] allocates 16 bytes of store for a string.
scanf() then reads a string into that store.
If you read in more than the amount of allocated store, memory is corrupted after the end of the store.
That's why you crash.
The problem is that if the user types more than the 15 characters which you have allocated space for, then the computer will merrily write all of them in memory past the end of your array. This will result in "undefined behavior" including crashing your program.
As others have noted, your fundamental problem is that you're allocating 16 characters for the string, and scanf will happily allow you to write past those 16 characters into memory that doesn't belong to you.
Be aware that C will allow you to do this with arrays generally, and understand how standard C strings work: you need to null-terminate them, meaning that you'll always need an extra space in the array for a null-terminating character \0.
There is a way to limit scanf with respect to C strings, using a field width specifier with %s, like so:
char input[17]; // room for 16 characters plus null-terminator
// here scanf will stop after reading 16 characters:
scanf("%16s", input);
With this code, you can safely use scanf to fill your string with no more than 16 characters, and scanf will null-terminate the string for you.
But as others have also noted, scanf is pretty poor at handling user input. It's usually better to use fgets and manage the input string on your own, piece-by-piece.