Comparing strings using strtock with parsed input - c

I am taking input and then parsing the string word by word, but I need to identify the type of each word and therefore need to be able to directly compare the first word of the string in input to one of my predefined commands.
My issue is that the input consists of a command and then its parameters so I have to parse through STDIN word by word but when I use strcmp it doesn't work unless I remove the parameters or include a space in my strcmp.
My code is below:
#include <string.h>
#include <stdio.h>
int main () {
char input[100];
printf("Enter your input: ");
fgets(input, 100, stdin);
printf("Reading input... \n");
const char s[2] = " ";
char *arg;
/* get the first token */
arg = strtok(input, s);
printf("First word: %s\n", arg);
if(strcmp(arg, "ATTACK")){
printf("Input Match\n");
}
return(0);
}
For instance, if I give the input of "ATTACK 50 40" it will not give me an Input Match despite the first word being ATTACK.
I tried checking what was being stored in my arg variable to ensure that strcmp was comparing the right thing and it seemingly was but I realized it was possible it was including the whitespace between the command and the parameters.
I tried adding a space in the strcmp's "ATTACK" so it became "ATTACK " and it worked but I was wondering if there is a way I can have a garbage collecting variable which will remove the whitespace from the variable or if I can specify to remove the last character if it is whitespace.

strcmp returns 0 if the strings are equal
do
if(strcmp(arg, "ATTACK") == 0){

Related

Unable to search character with string input from fgets

I'm writing a program to find the location of a certain character in a string using strchr. When using fgets to input the string from the user, the program does not execute properly.
However when using gets everything works fine.
Code that works using gets():
#include <stdio.h>
#include <string.h>
int main() {
char let;
char input[50];
char *ptr;
printf("what is the string that you would like to check?\n");
gets(input);
printf("what is the character that you would like to find?\n");
let = getchar();
printf("in string \"%s\"...\n", input);
ptr = strchr(input, let);
while (ptr != NULL) {
printf("the letter %c was found at character %d\n", let, ptr - input + 1);
ptr = strchr(ptr + 1, let);
}
return 0;
}
Output:
what is the string that you would like to check?
what is the character that you would like to find?
in string "why is the world when wondering"...
the letter w was found at character 1
the letter w was found at character 12
the letter w was found at character 18
the letter w was found at character 23
Code that does not work usgin fgets():
#include <stdio.h>
#include <string.h>
int main() {
char let;
char input[50];
char *ptr;
printf("what is the string that you would like to check?\n");
fgets(input, 16, stdin);
printf("what is the character that you would like to find?\n");
let = getchar();
printf("in string \"%s\"...\n", input);
ptr = strchr(input, let);
while (ptr != NULL) {
printf("the character is found at %d \n", ptr - input + 1);
ptr = strchr(ptr + 1, let);
}
return 0;
}
Output:
what is the string that you would like to check?
what is the character that you would like to find?
in string "abcdefghijklmno"...
Change
fgets(input, 16, stdin)
to
fgets(input, sizeof(input), stdin)
When you pass an argument of 16 to fgets() you are instructing it to read no more than 15 characters. Why?
From the fgets() manpage:
fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s.
If you provide more than size -1 characters, the remaining characters are left in the input buffer.
Then when the program subsequently calls
let = getchar();
let is assigned whatever the next character in the input buffer is - without even waiting for you to type anything else. It then searches for this character in the string you provided - but in the example you provided doesn't find it.
In the first code snippet the call
gets (input);
does not restrict the number of characters the user can input. Take into account that the function gets is not supported by the C Standard and is unsafe.
In the second code snippet you declared the variable input as
char input[50];
So it is more natural to call fgets the following way
fgets (input,sizeof( input ),stdin );
instead of
fgets (input,16,stdin);
The standard function getchar reads any character including white spaces.
So instead it it is much better to use
scanf( " %c", &let );
Otherwise getchar can read any character (including for example the new line character) leaved in the input buffer. While the call of scanf will skip any white space character.

How to check if user input numbers instead of string(array of char) in C

So, I got this assignment as a student that ask me to create a simple program using C.
This program input only allow you to input only characters A-Z, a-z, and (space).
and the length of the string should be no less than 1 character and no more than 100 characters.
So, I come with the conclusion that I should use if function to validate if the user input the allowed character.
#include <stdio.h>
#include <ctype.h>
int main()
{
char name[100];
scanf("%s",&name);
fflush(stdin);
if (isdigit(name))
^^^^
{
printf("Wrong answers");
getchar();
}
else
....
It was supposed to print "wrong answers" if you input numbers in there, but this program won't run.. It keeps saying :
error C2664: 'isdigit' : cannot convert parameter 1 from 'char [100]' to 'int'
I don't know what this error means.. Is there something I miss? Or am I using the wrong function?
I have also tried
if (((name>='A')&&(name<='Z'))||((name>='a')&&(name<='z')||)((name==' ')))
{
//this print what i want
}
else
{
printf("wrong answers");//this print "wrong answer"
}
but it always print "wrong answers" no matter I input the correct input or the wrong input.
Your help is highly appreciated.
Thank you.
*ps : I am a beginner at programming.
isdigit() takes an int as argument, not a char*:
int isdigit(int c);
You have to use a loop over the string and check each character in it.
Having said that, to achieve:
this program input only allow you to input only characters 'A'-'Z', 'a'-'z', and ' '(space)
you are better off using isalpha().
Try this out:
#include <stdio.h>
#include <ctype.h>
int main()
{
int i = 0;
char name[101], temp;
// take input one character at a time
while(scanf("%c", &temp)){
// stop when newline or carriage return
if(temp == '\n' || temp == '\0' || !isalpha(temp) ){
break;
}
// save character in array
name[i] = temp;
// move to the next position of the array
i++;
}
printf( "%s", temp );
return 0;
}
The problem you're seeing is that you're passing isdigit the wrong type of value - it expects an int, but you're passing it an array of char. You would have to loop over each and every character in your string to check if it's a digit or not.
But that is ultimately not what you're after as you're looking to confirm that the string contains letters or spaces - there are lots of characters that could be entered that aren't classed as digits that would be accepted incorrectly.
What would be the easiest solution for you, is to use the function strspn. It takes a string and returns the length of how many characters match the second parameter. If that length is the same length as your string, you know that it only contains valid characters.
size_t valid;
valid=strspn(name, "abcdefg(fill in with other valid characters)");
if(valid==strlen(name))
{
// Valid name
}
else
{
// Not valid
}
If you need to expand the accepted characters, it's just a simple case of adding them to the 2nd parameter.
OP's code fails as isdigit() test is a single character is a digit (0-9). It does not test a string.
int isdigit(int c);
The isdigit function tests for any decimal-digit character.
In all cases the argument is an int, the value of which shall be
representable as an unsigned char or shall equal the value of the macro EOF.
OP's buffer is too small to save 100 characters read from the user. At least 1 more needed to detect if too many were read and 1 more for a null character to mark the end of a string.
fflush(stdin); has its problems too.
scanf("%s",&name); does not save white-space. The parameter should have been name too. (no &)
Read a line of user input with fgets() which saves the result as a string.
Test if the input meets the criteria.
Read
#define N 100
// No need to be stingy on buffer size reading user input. Suggest 2x
// We need +1 for extra character detection, \n and \0
char buf[2*N + 1 + 1];
fgets(buf, sizeof buf, stdin);
// lop off potential \n
size_t length = strlen(buf);
if (length > 0 && buf[length-1] == '\n') {
buf[--length] = '\0';
}
Test
only characters 'A'-'Z', 'a'-'z', and ' '(space).
for (size_t i = 0; i<length; i++) {
if (!isalpha((unsigned char)buf[i]) && buf[i] != ' ') {
puts("Invalid chracter");
break;
}
}
length of the string should be no less than 1 character and no more than 100 characters.
if (length < 1 || length > 100) {
puts("Input wrong length");
}
Others approaches can be used to disqualify very long inputs. IMO, very long inputs represent an attack and should be handled differently than a simple line that was a bit too long.
if (length < 1 || length > 100) {
if (length + 2 >= sizeof buf) {
puts("Input way too long");
exit (EXIT_FAILURE);
}
puts("Input wrong length");
}
name must have one extra space for the \0 (NUL) character.
So to store 100 characters, its size should be at least 101.
char name[101];
You could first use
fgets(name, sizeof(name), stdin);
to read into name character array.
Note that fgets() will read in the trailing newline (\n) as well which need be removed like
name[strlen(name)-1]='\0';
Then use sscanf(). Like
size_t l=strlen(name);
sscanf(name, "%100[A-Za-z ]", name);
if(strlen(name)!=l)
{
printf("\nInvalid input.");
}
Note the space after the A-Za-z.
The 100 in the %100[A-Za-z] denotes reading at most 100 characters into name. The [A-Za-z ] will make the sscanf() stop reading if a non-alphabetic character which is not a space is encountered.
First read into name. Then store its length in l. Now read everything till a non-alphabet other than a space occurs in name to name itself (thereby modifying name).
Now compare the length of this new string with l. If they are the same. The input is valid as per your need.
You could also use scanf() instead of fgets() like
scanf("%100[^\n]", name);
which instructs to read every character till a \n into name. If this is used, no \n will added at the end of name unlike the case with fgets().
Now I would like to point out some mistakes in your code.
scanf("%s",&name);
will lead to errors. Correct one is
scanf("%s",name);
as the second argument here must be an address and since an array name in C decays into its base address, just name would do instead of &name.
As others have pointed out, using fflush() on stdin is undefined and must be avoided.
If you are trying to clear the input buffer till the next newline (\n), you could do
int ch;
while((ch=getchar())!='\n');// && ch!=EOF)
The argument of isdigit() must be a char and not a character array (type char [100] if size is 100).
And if is a statement and not a function.

C string compare wont allow space bar

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.

Store user input in a variable so that I can get a substring from it

In C Programming, how do I store user input in a variable so that I can get a substring from it?
When typing in "hello Point" in the console I get an error: The substring is NULL. This means my word variable is empty? What exactly did I do wrong and why?
#include <stdio.h>
#include <string.h>
int main()
{
char word[100];
printf ("Enter a word: ");
scanf ("%s", word);
const char needle[] = "Point";
char *ret;
ret = strstr(word, needle);
printf("The substring is: %s\n", ret);
return(0);
}
%s for scanf() stops reading when it found a whitespace.
Try using scanf ("%99[^\n]", word); instead. (added 99 to avoid buffer overrun)
strstr returns NULL if the substring is not found. This is the case here. You are using scanf to read string. It will stop scanning after first occurrence of a white space, an ' ' here. Therefore, only hello will be stored in word and strstr(word, needle) will return NULL.
Use fgets instead to read string.
fgets(word, sizeof(word), stdin);

Replacing part of string with another substring in C

this code is working perfectly fine in my compiler(DEV C++) but not in Ideone.com . It is not accepting replacement string. is there anything wrong with my logic ? May I know whats wrong with my code?
//splitting a string and replace latter part of string by another string
#include<stdio.h>
#include<string.h>
int i,count=0,loc2=0,scount=0,rcount=0,loc=0; //scount represents counter for substring and rcount for replacement and loc from where we will split the string
char str[100],sub[100],newss[100]; //newss=new substr, rslt and rslt2=former and latter part of original string
int main()
{
String();
substring();
new_string();
concat();
return 0;
}
void String()
{
printf("Enter a String:\n");
gets(str);
printf("\nString Entered by User:\n");
puts(str);
printf("\nLoc Char\n"); //Creates Colums 'Char' and 'Loc'
for(i=0;str[i]!='\0';i++)
{
count++; //Counts length of String
printf("%d. %c\n",count,str[i]); //Prints Characters with it its Corresponding Location
}
printf("\n\nLength of String: %d\n\n",count);
}
void substring()
{
printf("Enter the locations of Characters from where substring will start and end: \n");
scanf("%d%d",&loc,&loc2); //stores indices of begining and end of substring
printf("\n\nSubset formed from Existing String:\n");
for(i=loc-1;i<loc2;i++)
{
scount++;
sub[i]=str[i]; //stores substring in "sub"
printf("%c",sub[i]);
}
printf("\n\nLength of substring: %d\n",scount);
}
void new_string()
{
printf("\n\nEnter a Replacement for substring(Of Equal Length as that of substring):\n");
fflush(stdin);
gets(newss);
for(i=0;newss[i]!='\0';i++)
rcount++;
printf("\n\nLength of New substring: %d\n",rcount); //-1 to subtract length of null char
}
void concat()
{
if(rcount!=scount) //to check whether replacement string and substring are of same length
printf("\nSince length of both substrings is not same. \nHence Replacement is Not Possible\n");
else //Concatination of 3 substrings
{
printf("\nResultant String:\n");
for(i=0;i<(loc-1);i++)
printf("%c",str[i]);
for(i=0;newss[i]!='\0';i++)
printf("%c",newss[i]);
for(i=loc2;str[i]!='\0';i++)
printf("%c",str[i]);
}
}
You're doing a number of strange things, and some bad things as well, one of the big problems is you're intermixing calls to gets() and scanf(), they handle new line characters differently and it's getting you in trouble.
When you call substring() it's using scanf() to get the two substring indexes, but it's leaving a newline character('\n') on stdin, then your call to gets() is reading that and using it as the string.
Change:
gets(newss);
To:
scanf(" %s", newss);
And things will work in ideone.com.
You maybe wondering why did you have this problem when you called fflush(stdin); just before reading newss. This is part of what I described as "bad things" before. fflush(stdin) should NEVER be done. This leads to undefined behavior, fflush() is well defined for stdout but not for stdin. This means calling it could flush the input buffer or it could not it depends on how that was implemented in the IDE you were using (or if it was at all). If it's not defined in the C standard, you can't assume it will work.
EDIT:
your example is using spaces in the substring you're entering so the answer is the same, but you need to use the negated scanset:
scanf(" %[^\n]", newss); // note my examples start with a blank space
// ^
// |
// here
The blank space will tell scanf() to ignore any remaining "white space" characters left on stdin, that means that left over '\n' will not be considered. However that ALSO means that if your replacement string starts with a space that space will be ignored. You can read the man page for scanf() and consider exactly what you want to use for your input string based on your assignment requirements.

Resources