strcmp return value is wrong (beginner) [duplicate] - c

This question already has answers here:
strcmp on a line read with fgets
(6 answers)
Closed 5 years ago.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void getSentence(char userSentence[]);
int breakSentence_andCompare(char userSentence[] , char compareSentence[]);
#define MAX_SENTENCE 100
int main()
{
int len = 0;
char userSentence[MAX_SENTENCE] = {'o','k',0};
char compareSentence[MAX_SENTENCE] = {'o',0};
getSentence(userSentence);
len = breakSentence_andCompare(userSentence,compareSentence);
}
/*
This function is asking the user to input info.
input:user input string array - char userSentence[].
output:none.
*/
void getSentence(char userSentence[])
{
printf("Hello And Welcome To The Palindrome Cheker Made By xXTH3 SKIRT CH4S3RXx");
printf("\nPlease Enter A Sentence: ");
fgets(userSentence,MAX_SENTENCE,stdin);
}
/*
This function takes the input of the user and input it into another string backwards.
input:user input string array - char userSentence[], backward user input string array - char compareSentence[].
output:strcmp value.
*/
int breakSentence_andCompare(char userSentence[] , char compareSentence[])
{
int i = 0;
int z = 0;
int len = 0;
int cmp = 0;
len = strlen(userSentence);
len -= 1;
for (i = len ; i >= 0 ; i--)
{
compareSentence[z] = userSentence[i];
printf("%s",compareSentence);
z++;
}
printf("\nuser: %s! compare: %s!",userSentence,compareSentence);
cmp = strcmp(userSentence,compareSentence);
printf("\n%d",&cmp);
return cmp;
}
This program checks if inputted string is palindrome,
To simply explain how it works:
It takes user input - String.
It Takes the user string and input is backwards in another string.
It compares the strings.
I have a really strange problem in the function and that's the strcmp return value. For some reason, when both strings have the same characters like ABBA the strcmp will return that the value of one of them is bigger. I'd really love to know what is the problem and how can I fix it.
P.S
When I were searching the problem I thought that it might be connected to fact that the user input string might contain \n from the enter key; is that possible?
And please understand that this isn't a whole code. The code is missing the output part.

The problem is occurring because of trailing \n (newline) character in user input string.
fgets()
The fgets() function shall read bytes from stream into the array
pointed to by s, until n-1 bytes are read, or a is read
and transferred to s, or an end-of-file condition is encountered.
The string is then terminated with a null byte. [EMPHASIS MINE]
So, a newline character makes fgets stop reading, but it is considered a valid character by the function and included in the input string.
Say, user input string is "ABBA". So, after entering the input the content of userSentence will be "ABBA\n".
In your program, you are reversing the input string and comparing it with the original input string.
After reversing, the content of compareSentence will be "\nABBA".
The content of both the strings are not same and the strcmp() will return non zero value as the comparison result.
There are various ways of removing trailing \n (newline) character from fgets() input. Check this.
Since you are a beginner, so one suggestion to you - Don't ignore the compiler warning('s).
For the statement -
printf("\n%d",&cmp);
You must be getting a warning message during compilation of your program.
You should try to identify the cause of warning message('s) and should resolve them.
There are much better ways to find out the whether a string is palindrome or not but since you are a beginner, your start is good. Happy Learning.. :)

Related

fgets reading more char than it should

I'm developing a code where the user will type several paragraphs and it will stop reading when the user begin a paragraph with "END". The code will manipulate the string by counting each letter and showing a graph and blah blah blah, but this is irrelevant to the question.
The thing is: which paragraph must have no more than 1000 characters.
A smaller version of the code is the following (considering I just want to storage 5-char-string - even though I'll expand that).
#include <stdio.h>
#include <string.h>
int main()
{
char paragraph[5];
for ( ; ; )
{
fgets(paragraph, 5, stdin);
if (paragraph[0]=='E' && paragraph[1]=='N' && paragraph[2]=='D')
{ return 0; }
printf("%s", paragraph);
}
return 0;
My problem is: if I type more than 5 characters, the printf function still prints more than 5 characters, I don't know why. I've already checked everything I could possible check.
Help a beginner like me, please.
fgets() reads in at most one less than size characters from stream and
stores them into the buffer pointed to by s. Reading stops after an
EOF or a newline. If a newline is read, it is stored into the buffer.
A terminating null byte ('\0') is stored after the last character in
the buffer.
So when entering more than 4 characters (newline included) only 4 is read and the rest stays in the buffer ready to be read next fgets.
Your printf will not print any newline in this case and will be called multiple times, making it look like printing more than 4 characters.
As suggested in comments, try printf("[%s]", paragraph); to see the individual printf calls.
You should use strstr in string.h because it's cleaner.
if (strstr(paragraph, "END"))
return 0;
instead of
if (paragraph[0]=='E' && paragraph[1]=='N' && paragraph[2]=='D')
return 0;
Try modifying your code in the following way and you'll immediately see what actually happens with the fgets() function when you enter more characters than the size of your buffer. It doesn't read from the keyboard, but from the stdinbuffer. These SO posts may also be interesting for you to read:(1), (2). Enjoy the demo and be sure to thoroughly read the man pages.
#include <stdio.h>
int main()
{
char paragraph[5];
for ( ; ; )
{
printf("Enter the string: \n\t");
if(fgets(paragraph, 5, stdin) != NULL)
printf("%s\n", paragraph);
if (paragraph[0]=='E' && paragraph[1]=='N' && paragraph[2]=='D')
return 0;
}
return 0;
}

How to correctly input a string in C

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.

Why fgets is not inputting first value?

I am writing a program to write my html files rapidly. And when I came to write the content of my page I got a problem.
#include<stdio.h>
int main()
{
int track;
int question_no;
printf("\nHow many questions?\t");
scanf("%d",&question_no);
char question[question_no][100];
for(track=1;track<=question_no;track++)
{
printf("\n<div class=\"question\">%d. ",track);
printf("\nQuestion number %d.\t",track);
fgets(question[track-1],sizeof(question[track-1]),stdin);
printf("\n\n\tQ%d. %s </div>",track,question[track-1]);
}
}
In this program I am writing some questions and their answers (in html file). When I test run this program I input the value of question_no to 3. But when I enter my first question it doesn't go in question[0] and consequently the first question doesn't output. The rest of the questions input without issue.
I searched some questions on stackoverflow and found that fgets() looks for last \0 character and that \0 stops it.
I also found that I should use buffer to input well through fgets() so I used: setvbuf and setbuf but that also didn't work (I may have coded that wrong). I also used fflush(stdin) after my first and last (as well) scanf statement to remove any \0 character from stdin but that also didn't work.
Is there any way to accept the first input by fgets()?
I am using stdin and stdout for now. I am not accessing, reading or writing any file.
Use fgets for the first prompt too. You should also malloc your array as you don't know how long it is going to be at compile time.
#include <stdlib.h>
#include <stdio.h>
#define BUFSIZE 8
int main()
{
int track, i;
int question_no;
char buffer[BUFSIZE], **question;
printf("\nHow many questions?\t");
fgets(buffer, BUFSIZE, stdin);
question_no = strtol(buffer, NULL, 10);
question = malloc(question_no * sizeof (char*));
if (question == NULL) {
return EXIT_FAILURE;
}
for (i = 0; i < question_no; ++i) {
question[i] = malloc(100 * sizeof (char));
if (question[i] == NULL) {
return EXIT_FAILURE;
}
}
for(track=1;track<=question_no;track++)
{
printf("\n<div class=\"question\">%d. ",track);
printf("\nQuestion number %d.\t",track);
fgets(question[track-1],100,stdin);
printf("\n\n\tQ%d. %s </div>",track,question[track-1]);
}
for (i = 0; i < question_no; ++i) free(question[i]);
free(question);
return EXIT_SUCCESS;
}
2D arrays in C
A 2D array of type can be represented by an array of pointers to type, or equivalently type** (pointer to pointer to type). This requires two steps.
Using char **question as an exemplar:
The first step is to allocate an array of char*. malloc returns a pointer to the start of the memory it has allocated, or NULL if it has failed. So check whether question is NULL.
Second is to make each of these char* point to their own array of char. So the for loop allocates an array the size of 100 chars to each element of question. Again, each of these mallocs could return NULL so you should check for that.
Every malloc deserves a free so you should perform the process in reverse when you have finished using the memory you have allocated.
malloc reference
strtol
long int strtol(const char *str, char **endptr, int base);
strtol returns a long int (which in the code above is casted to an int). It splits str into three parts:
Any white-space preceding the numerical content of the string
The part it recognises as numerical, which it will try to convert
The rest of the string
If endptr is not NULL, it will point to the 3rd part, so you know where strtol finished. You could use it like this:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char * endptr = NULL, *str = " 123some more stuff";
int number = strtol(str, &endptr, 10);
printf("number interpreted as %d\n"
"rest of string: %s\n", number, endptr);
return EXIT_SUCCESS;
}
output:
number interpreted as 123
rest of string: some more stuff
strtol reference
This is because the previous newline character left in the input stream by scanf(). Note that fgets() stops if it encounters a newline too.
fgets() reads in at most one less than size characters from stream and
stores them into the buffer pointed to by s. Reading stops after an
EOF or a newline. If a newline is read, it is stored into the
buffer
Don't mix fgets() and scanf(). A trivial solution is to use getchar() right after scanf() in order to consume the newline left in the input stream by scanf().
As per the documentation,
The fgets() function shall read bytes from stream into the array
pointed to by s, until n-1 bytes are read, or a < newline > is read and
transferred to s, or an end-of-file condition is encountered
In case of scanf("%d",&question_no); a newline is left in the buffer and that is read by
fgets(question[track-1],sizeof(question[track-1]),stdin);
and it exits.
In order to flush the buffer you should do,
while((c = getchar()) != '\n' && c != EOF)
/* discard */ ;
to clear the extra characters in the buffer

I don't understand the behavior of fgets in this example

While I could use strings, I would like to understand why this small example I'm working on behaves in this way, and how can I fix it ?
int ReadInput() {
char buffer [5];
printf("Number: ");
fgets(buffer,5,stdin);
return atoi(buffer);
}
void RunClient() {
int number;
int i = 5;
while (i != 0) {
number = ReadInput();
printf("Number is: %d\n",number);
i--;
}
}
This should, in theory or at least in my head, let me read 5 numbers from input (albeit overwriting them).
However this is not the case, it reads 0, no matter what.
I understand printf puts a \0 null terminator ... but I still think I should be able to either read the first number, not just have it by default 0. And I don't understand why the rest of the numbers are OK (not all 0).
CLARIFICATION: I can only read 4/5 numbers, first is always 0.
EDIT:
I've tested and it seems that this was causing the problem:
main.cpp
scanf("%s",&cmd);
if (strcmp(cmd, "client") == 0 || strcmp(cmd, "Client") == 0)
RunClient();
somehow.
EDIT:
Here is the code if someone wishes to compile. I still don't know how to fix
http://pastebin.com/8t8j63vj
FINAL EDIT:
Could not get rid of the error. Decided to simply add #ReadInput
int ReadInput(BOOL check) {
...
if (check)
printf ("Number: ");
...
# RunClient()
void RunClient() {
...
ReadInput(FALSE); // a pseudo - buffer flush. Not really but I ignore
while (...) { // line with garbage data
number = ReadInput(TRUE);
...
}
And call it a day.
fgets reads the input as well as the newline character. So when you input a number, it's like: 123\n.
atoi doesn't report errors when the conversion fails.
Remove the newline character from the buffer:
buf[5];
size_t length = strlen(buffer);
buffer[length - 1]=0;
Then use strtol to convert the string into number which provides better error detection when the conversion fails.
char * fgets ( char * str, int num, FILE * stream );
Get string from stream.
Reads characters from stream and stores them as a C string into str until (num-1) characters have been read or either a newline or the end-of-file is reached, whichever happens first.
A newline character makes fgets stop reading, but it is considered a valid character by the function and included in the string copied to str. (This means that you carry \n)
A terminating null character is automatically appended after the characters copied to str.
Notice that fgets is quite different from gets: not only fgets accepts a stream argument, but also allows to specify the maximum size of str and includes in the string any ending newline character.
PD: Try to have a larger buffer.

Input an arbitrary number of strings from the user [duplicate]

This question already has answers here:
How can I read an input string of unknown length?
(11 answers)
Closed 4 years ago.
I want to read in an arbitrary number of strings, one at a time, using <stdio.h> in C.
I know that you can do this with integers using:
while (scanf("%d ", &integer))
but I cannot do:
while (scanf("%s", string))
How can I implement the above?
The input is on separate lines.
You usually want to use fgets to read input as strings, especially when you want one line of input to end up as one string.
You can also use fscanf with a scanset conversion to read a line at a time, such as:
char line[100], newline;
fscanf("%99[^\n]%c", line, &newline);
Then you can check whether newline=='\n' to determine whether you've read the entire line successfully, or the line was larger than the buffer you provided.
When you're trying to read line-oriented input, you normally want to avoid "%s" (even with a specified length) though, as this reads white-space delimited tokens, not entire lines.
Use a char array:
char charArray[100];
while (scanf("%s", &charArray))
I guess your problem is to terminate the loop. scanf returns the number of successful scanned elements. In case of a string, also the empty string is successful scanned. Thus, you need another criterion, e.g.
while(scanf("%s",string) && (strlen(string)!=0))
I did not completely understand what you were trying to do from your original question. When you said you wanted to read in an arbitrary number of strings, I took that to mean, you wanted your program to be able to read 0 to n strings. Unfortunately in C, you will either have to cap off the maximum number of strings you would ever want to read in like
#define MAX_NUMBER_OF_STRINGS_TO_READ 25, or get into some sophisticated memory allocation scheme to read a string in and then add it to dynamic memory (returned from malloc).
I took the cap the maximum number of strings approach and wrote the following snippet:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char charArray[5][25] = {0};
int main(int argc, char *argv[])
{
int in_idx = 0;
int out_idx = 0;
printf("\n\n%s\n", "Enter no more than 5 strings, no more than 25 characters long.");
while(fgets (charArray[in_idx], 25, stdin))
{
if('\n' == charArray[in_idx][0])
{
printf("%s\n", "Entry terminated with newline.");
break;
}
in_idx++;
}
for(out_idx=0; out_idx < (in_idx + 1); out_idx++)
{
printf("%s", charArray[out_idx]);
}
printf("\n%s\n", "Program ended.");
return 0;
}
I made the termination character a newline. If I only want two strings, I press Enter when I've entered the second string. I terminated fgets by looking for a '\n' in the first position of the character array.

Resources