C string compare wont allow space bar - c

using the cprogrammingsimplified tutorial for writing my own stringcompare.
Finished reformatting it and ran it.
works fine for single words,
But
typing space bar skips the second scan and immediately outputs
'words aren't the same'
anyone any idea how to allow the use of even a single space bar?
Thanks in advance.
#include <stdio.h>
int mystrcmp(char s1[], char s2[]);
int main(){
char s1[10], s2[10];
int flag;
printf("Type a string of 10\n\n");
scanf("%s",&s1);
printf("type another string of 10 to compare\n\n");
scanf("%s",&s2);
flag = mystrcmp(s1,s2);
if(flag==0)
printf("the words are the same\n\n");
else
printf("the words are not the same\n\n");
return 0;
}
int mystrcmp(char s1[], char s2[]){
int l=0;
while (s1[l] == s2[l]) {
if (s1[l] == '\0' || s2[l] == '\0')
break;
l++;
}
if (s1[l] == '\0' && s2[l] == '\0')
return 0;
else
return -1;
}

Use fgets() to read full lines, rather than scanf() to read space-separated words.
Remember that fgets() will include the linefeed in the string, though.

It is not strcmp that wouldn't allow space bar, it's scanf with %s format specifier. The input is truncated at the space, so the second string that you read is actually the continuation of the first string.
You can fix this by using %9[^\n] instead of %s in your format specifier:
printf("Type a string of 10\n\n");
scanf("%9[^\n]",s1); //s1 is char [10]
printf("type another string of 10 to compare\n\n");
scanf("%9[^\n]",s2); //s2 is char [10]
9 limits input to nine characters, because you are using a ten-character buffer.

Many answers have told you that scanf("%s",s1) only reads word by word. This is because by default scanf("%s",s1) is delimited by all white spaces, this includes \t, \n, <space>, or any other you can think of.
What scanf("%[^\n]s",s1) does is set the delimiter to \n. So in effect reads all other spaces.
#dasablinklight has also specified a 9 before the '[^\n]' this denotes that scanf() takes 9 values from input buffer.
IMO scanf() is a really nice function due to it's hidden features. I suggest you read more about it in it's documentation.

The problem is that if you type abc def on the first line, the first scanf("%s", s1) (no ampersand required — it should be absent) reads abc and the second reads def. And those are not equal. Type very very and you'd find the words are equal. %s stops reading at a space.
Your buffers of size 10 are too small for comfort.
Fix: read lines (e.g. char s1[1024], s2[1024];) with fgets() or POSIX's getline(), remove trailing newlines (probably: s1[strcspn(s1, "\n")] = '\0'; is a reliable way to do it) and then go ahead compare the lines.

Related

Counting the Whole String Including The Spaces in C

I'm trying to set up a code that counts the whole string and doesn't stop after the first space that it finds. How do I do that?
I tried this kind of code but it just counts the first word then goes to display the number of letters in that first word.
So far this is what I have tried.
int main(){
char get[100];
int i, space=0, len=0, tot;
scanf("%s", get);
for (i=0; get[i]!='\0'; i++)
{
if (get[i] == ' ')
space++;
else
len++;
}
tot = space + len;
printf("%i", tot);
}
And
int main(){
char get[100];
int len;
scanf("%s", &get);
len = strlen(get);
printf("%i", len);
}
But would still get the same answer as the first one.
I expected that if the
input: The fox is gorgeous.
output: 19
But all I get is
input: The fox is gorgeous.
output: 3
strlen already includes spaces, since it counts the length of the string up to the terminating NUL character (zero, '\0').
Your problem is that that the %s conversion of scanf stops reading when it encounters whitespace, so your string never included it in the first place (you can verify this easily by printing out the string). (You could fix it by using different scanf conversions, but in general it's easier to get things right by reading with fgets – it also forces you to specify the buffer size, fixing the potential buffer overflow in your current code.)
The Answer by Arkku is correct in its diagnose.
However, if you wish to use scanf, you could do this:
scanf("%99[^\n]", get);
The 99 tells scanf not to read more than 99 characters, so your get buffer won't overflow. The [^\n] tells scanf to read any character until it encounters the newline character (when you hit enter).
As Chux pointed out, the code still has 2 issues.
When using scanf, it is always a good idea to check its return value, which is the number of items it could read. Also, indeed the \n remains in the input buffer when using the above syntax. So, you could do this:
if(scanf("%99[^\n]", get) == 0){
get[0] = 0; //Put in a NUL terminator if scanf read nothing
}
getchar(); //Remove the newline character from the input buffer
I will take one example to explain the concept.
main()
{
char s[20], i;
scanf("%[^\n]", &s);
while(s[i] != '\0') {
i++;
}
printf("%d", i);
return 0;
}
i have used c language and u can loop through the ending the part of the string and you will get the length. here i have used "EDIT SET CONVESRION METHOD" to read string, you can also gets to read.

Why does the presence of `n` in the input sentence before `\n` give wrong output?

I want to input a sentence (containing any possible characters) and print it. But there is a catch. If there is a \n in the sentence then only the part of the sentence before \n should be printed out (i.e. \n should signify the end of the inputted sentence). I wrote a code for this situation :
#include <stdio.h>
main()
{
char ch[100];
printf("Enter a sentence");
scanf("%99[^\\n]",&ch);
printf("%s",ch);
}
This code seems to work fine but it fails in a certain situation.
If there is the character n anywhere in the sentence before \n then it prints only the first word of the sentence! Why does this happen? How can I fix this bug?
This case works fine:
But in this case it fails:
Detail from comments:
Q: Do you want to to stop at a newline, or at a backslash followed by n?
A: slash followed by n
The [] conversion specifier of scanf() works by defining an accepted (or, with ^, rejected) set of characters. So %[^\\n] will stop scanning at the first \ or the first n -> You can't solve your problem with scanf().
You should just read a line of input with fgets() and search for an occurence of "\\n" with strstr().
Side note: there's an error in your program:
char ch[100];
scanf("%99[^\\n]",&ch);
ch evaluates as a pointer to the first element of the array (so, would be fine as parameter for scanf()), while &ch evaluates to a pointer to the array, which is not what scanf() expects.
(the difference is in the type, the address will be the same)
OP's calcification negated the first part of this answer.
OP has not formed the desired scan set for the "%[...]" specifier.
"%99[^\\n]" accepts any character except '\\' and 'n'.
Certainly OP wants "%99[^\n]". \\ changed to \ to accept any character except '\n'.
Yet I would like to take the goal up a bit. This part is only for pedantic code.
input a sentence (containing any possible characters)
How would code handle this if the null character '\0' was included in that "any possible character"?
Note that inputting a null character is not often easy from a keyboard.
Interestingly "%99[^\n]" will scan up to 99 characters (except a '\n') including the null character. Yet the below code prints ch as it it were a string and not a general array of characters.
#include <stdio.h>
int main(void) {
char ch[100];
printf("Enter a sentence\n");
if (scanf("%99[^\n]", ch) != 1) {
ch[0] = '\0'; // Handle a line of only `'\n``, EOF, or error
}
printf("%s",ch);
}
To accomplish this esoteric goal with scanf() (not the best tool in the shed), record the length of the scan and then print the array.
int main(void) {
char ch[100];
int n;
printf("Enter a sentence\n");
if (scanf("%99[^\n]%n", ch, &n) != 1) {
n = 0; // If scanning stopped right away, set length `n` to 0
}
// Write as an array
fwrite(ch, sizeof ch[0], n, stdout);
}

Search whitespace in string inC

problem is when I try to enter a string with space compiler render that as separate 2 strings. But requirement is whenever there is a space in string don't treat it as 2 strings,but rather a single string. The program should print yes only if my four inputs are MAHIRL,CHITRA,DEVI and C. my code is:
#include<stdio.h>
#include<string.h>
int main()
{
char str1[10],str2[10],str3[10],str4[10];
scanf("%s",str1);
scanf("%s",str2);
scanf("%s",str3);
scanf("%s",str4);
if(strcmp(str1,"MAHIRL")==0 && strcmp(str2,"CHITRA")==0 && strcmp(str3,"DEVI")==0 && strcmp(str4,"C")==0 ){
printf("yes");
}
else{
printf("no");
}
return 0;
}
I tried using strtok() and strpbrk(), but I'm not quite sure how to implement them in my code. Any help or suggestion is appreciated. Thanks.
problem is when I try to enter a string with space compiler render that as separate 2 strings
That's not a problem, that's the feature / behaviour of %s format specifier with scanf(). You cannot read space-delimited input using that.
For conversion specifier s, chapter §7.21.6.2, C11
s Matches a sequence of non-white-space characters. [...]
So, the matching ends as soon as it hits a white-space character, here, the space.
If you have to read a line (i.e., input terminated by newline), use fgets() instead.
The %s directive matches characters up to a whitespace before storing them, so it is not possible to get lines of input this way. There are other ways to use scanf() to read lines of input, but these are error-prone, and this is really not the right tool for the job.
Better to use fgets() to fetch a line of input to a buffer, and sscanf() to parse the buffer. Since the requirement here is that four strings are entered, this is a simple problem using this method:
#include <stdio.h>
#include <string.h>
int main(void)
{
char str1[10],str2[10],str3[10],str4[10];
char buffer[100];
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
fprintf(stderr, "Error in fgets()\n");
return 1;
}
if (sscanf(buffer, "%9s%9s%9s%9s", str1, str2, str3, str4) == 4) {
if (strcmp(str1,"MAHIRL") == 0 &&
strcmp(str2,"CHITRA") == 0 &&
strcmp(str3,"DEVI") == 0 &&
strcmp(str4,"C") == 0 ){
printf("yes\n");
} else {
printf("no\n");
}
} else {
printf("Input requires 4 strings\n");
}
return 0;
}
An additional character array is declared, buffer[], with enough extra space to contain extra input; this way, if the user enters some extra characters, it is less likely to interfere with the subsequent behavior of the program. Note that fgets() returns a null pointer if there is an error, so this is checked for; an error message is printed and the program exits if an error is encountered here.
Then sscanf() is used to parse buffer[]. Note here that maximum widths are specified with the %s directives to avoid buffer overflow. The fgets() function stores the newline in buffer[] (if there is room), but using sscanf() in this way avoids needing to further handle this newline character.
Also note that sscanf() returns the number of successful assignments made; if this return value is not 4, the input was not as expected and the values held by str1,..., str4 should not be used.
Update
Looking at this question again, I am not sure that I have actually answered it. At first I thought that you wanted to use scanf() to read a line of input, and extract the strings from this. But you say: "whenever there is a space in string don't treat it as 2 strings", even though none of the test input in your example code contains such spaces.
One option for reading user input containing spaces into a string would be to use a separate call to fgets() for each string. If you store the results directly in str1,...,str4 you will need to remove the newline character kept by fgets(). What may be a better approach would be to store the results in buffer again, and then to use sscanf() to extract the string, this time including spaces. This can be done using the scanset directive:
fgets(buffer, sizeof buffer, stdin);
sscanf(buffer, " %9[^\n]", str1);
The format string here contains a leading space, telling sscanf() to skip over zero or more leading whitespace characters. The %[^\n] directive tells sscanf() to match characters, including spaces, until a newline is encountered, storing them in str1[]. Note that a maximum width of 9 is specified, leaving room for the \0 terminator.
If you want to be able to enter multiple strings, each containing spaces, on the same line of user input, you will need to choose a delimiter. Choosing a comma, this can be accomplished with:
fgets(buffer, sizeof buffer, stdin);
sscanf(buffer, " %9[^,], %9[^,], %9[^,], %9[^,\n]", str1, str2, str3, str4);
Here, there is a leading space as before, to skip over any stray whitespace characters (such as \n characters) that may be in the input. The %[^,] directives tell sscanf() to match characters until a comma is encountered, storing them in the appropriate array (str1[],..., str3[]). The following , tells sscanf() to match one comma and zero or more whitespace characters before the next scanset directive. The final directive is %[^,\n], telling sscanf() to match characters until either a comma or a newline are encountered.
#include <stdio.h>
#include <string.h>
int main(void)
{
char str1[10],str2[10],str3[10],str4[10];
char buffer[100];
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
fprintf(stderr, "Error in fgets()\n");
return 1;
}
/* Each individual string str1,..., str4 may contain spaces */
if (sscanf(buffer, " %9[^,], %9[^,], %9[^,], %9[^,\n]",
str1, str2, str3, str4) == 4) {
if (strcmp(str1,"test 1") == 0 &&
strcmp(str2,"test 2") == 0 &&
strcmp(str3,"test 3") == 0 &&
strcmp(str4,"test 4") == 0 ){
printf("yes\n");
} else {
printf("no\n");
}
} else {
printf("Input requires 4 comma-separated strings\n");
}
return 0;
}
Here is a sample interaction with this final program:
test 1, test 2, test 3, test 4
yes
While reading strings from user, use __fpurge(stdin) function from stdio_ext.h. This flushes out the stdin. When you are entering a string, you press enter at last, which is also a character. In order to avoid that, we use fpurge function.
scanf("%s",str1);
__fpurge(stdin);
scanf("%s",str2);
__fpurge(stdin);
scanf("%s",str3);
__fpurge(stdin);
scanf("%s",str4);
__fpurge(stdin);
Also if you want to input a string from user containing spaces, use following:
scanf("%[^\n]", str1);
This will not ignore the spaces you enter while inputting string.
EDIT: Instead of using fpurge function, one can use following code:
while( getchar() != '\n' );

Scanf: detect that the input was too long

We can easily limit the length of the input accepted by scanf:
char str[101];
scanf("%100s", str);
Is there any efficient way to find out that the string was trimmed? We could, for example, report an error in such case.
We could read "%101s" into char strx[102] and check with strlen() but this involves extra cost.
Use the %n conversion to write the scan position to an integer. If it was 100 past the beginning then the string was too big.
I find that %n is useful for all kinds of things.
I thought the above was plenty of information for anyone who had read the scanf docs / man page and had actually tried it.
The idea is that you make your buffer and your scan limit bigger than whatever size string you expect to find. Then if you find a scan result that is exactly as big as your scan limit you know it is an invalid string. Then you report an error or exit or whatever it is that you do.
Also, if you're about to say "But I want to report an error and continue on the next line but scanf left my file in an unknown position."
That is why you read a line at a time using fgets and then use sscanf instead of scanf. It removes the possibility of ending the scan in the middle of the line and makes it easy to count line numbers for error reporting.
So here is the code that I just wrote:
#include <stdio.h>
#include <stdlib.h>
int scan_input(const char *input) {
char buf[101];
int position = 0;
int matches = sscanf(input, "%100s%n", buf, &position);
printf("'%s' matches=%d position=%d\n", buf, matches, position);
if (matches < 1)
return 2;
if (position >= 100)
return 3;
return 0;
}
int main(int argc, char *argv[]) {
if (argc < 2)
exit(1);
const char *input = argv[1];
return scan_input(input);
}
And here is what happens:
$ ./a.out 'This is a test string'
'This' matches=1 position=4
$ ./a.out 'This-is-a-test-string'
'This-is-a-test-string' matches=1 position=21
$ ./a.out '01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789'
'0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789' matches=1 position=100
You could use fgets() to read an entire line. Then you verify if the newline character is in the string. However, this has a few disadvantages:
It will consume the entire line, and maybe that's not what you want. Notice that fgets() is not equivalent to scanf("%100s") -- the latter only reads until the first blank character appears;
If the input stream is closed before a newline character is supplied, you will be undecided;
You have to go through the array to search for the newline character.
So the better option seems to be as such:
char str[101];
int c;
scanf("%100s", str);
c = getchar();
ungetc(c, stdin);
if (c == EOF || isspace(c)) {
/* successfuly read everything */
}
else {
/* input was too long */
}
This reads the string normally and checks for the next character. If it's a blank or if the stream has been closed, then everything was read.
The ungetc() is there in case you don't want your test to modify the input stream. But it's probably unnecessary.
fgets() is a better way to go, read the line of user input and then parse it.
But is OP still wants to use scanf()....
Since it is not possible to "detect that the input was too long" without attempting to read more than the n maximum characters, code needs to read beyond.
unsigned char sentinel;
char str[101];
str[0] = '\0';
if (scanf("%100s%c", str, &sentinel) == 2) {
ungetc(sentential, stdin); // put back for next input function
if (isspace(sentential) NoTrimOccurred();
else TrimOccurred();
else {
NoTrimOccurred();
}
A very rough but easy way of doing this would be, adding a getchar() call after the scanf().
scanf() leaves the newline into the input buffer after reading the actual input. In case, the supplied input is less than the maximum field width, getchar() would return the newline. Otherwise, the first unconsumed input will be returned.
That said, the ideal way of doing it is to actually read a bit more than the required value and see if anything appears in the buffer area. You can make use of fgets() and then, check for the 100th element value to be a newline or not but this also comes with additional cost.

Incorrect output, simple strings exercise - C

I am trying to write a function that gets a string of letters, either capital letters or small letters, and prints 2 other strings, one with only the capitals, and one only with the small letters. for example:
input: AaBbCcDD
Output: Capital string is ABCDD, non capital is abc
My code is not working correctly, it seems to skip over the last letter. To test it, I wrote the following code:
int length;
printf("Please enter length of string\n");
scanf("%d",&length);
string=create_string(length);
scan_string(string,length);
printf("The string entered is: \n");
print_string(string,length);
Where create_string is:
char* create_string(int size)
{
char* string;
string=(char*)malloc(size*sizeof(char));
return string;
}
Scan string is:
void scan_string(char* string, int size)
{
int i;
printf("Please enter %d characters\n",size);
for(i=0;i<size;i++)
scanf("%c",string+i);
}
And print string is
void print_string(char* string,int size)
{
int i;
for(i=0;i<size;i++)
printf("%c ",*(string+i));
}
When I try even just to print the string I entered, this is what I get, after I input aaAAB
The output is a a A A.
it skipped over the B.
The problem is with the scanf that reads characters using %c: it follows the scanf that reads the length using %d, which leaves an extra '\n' character in the buffer before the first character that you get.
If you modify the output to put quotes around your characters, you would actually see the \n:
void print_string(char* string,int size)
{
int i;
for(i=0;i<size;i++)
printf("'%c' ",*(string+i));
}
This prints
'
' 'a' 'a' 'A' 'A'
(demo on ideone)
You can change your first scanf to read '\n' as below. This will read the extra '\n'
scanf("%d\n", &length);
I think your code is unnecessarily elaborated. To read a string the function fget() with parameter stdin is a simpler choice.
For example, I wuold not ask to the user for the length of the string.
Perhaps it is better to use a buffer with fixed length, and to restrit the user to enter a string with the length less than which you have been previously stipulated.
#define MAXLEN 1000
char buffer[MAXLEN] = "";
fgets(buffer, MAXLEN, stdin);
If the user attempts to enter a string with more than MAXLEN characters, it would be necessary to handle the end-of-line in some way, but I think this is out of topic.
So, in general, let us suppose that MAXLEN is large enough such that buffer contains the \n mark.
Now, a call to your function print_string() can be done.
However, it would be better to do this:
printf("%s", buffer);
I think that you probably need to take in account the C convention for strings: a string is a char array whose last element is marked with the character '\0' (null character, having always code 0).
Even if you want to insist in your approach, I think that scanf() is a bad choice to read individual characters. it is more easy to use getchar(), instead.
By using scanf() you have to broke your brain figurating out all the stuff around the behaviour of scanf(), or how to handle the read of characters, and so on.
However, getchar() reads one char at a time, and that's (almost) all. (Actually, the console commonly not returns the control to the user until an end-of-line \n has been read).
string[i] = getchar();
The problem is because the scanf does not eat the "\n". Hence there is still one '\n' remaining at your first input. This will be counted at the next scanf.
Try to put an additional getchar() right after your first scanf.
printf("Please enter length of string\n");
scanf("%d",&length);
getchar(); // remove '\n'
string=create_string(length);

Resources