Taking multiple strings and integers in a single line - c

I want to take multiple integer and strings in a single line such as "45 A4 Paper 217" but I want to store string A4 Paper in a single char array. I tried using scanf but it scans until space for string.
int int1;
int int2;
char str1[81];
scanf("%d %s %d",&int1,&str1,&int2);
I want str1 to be A4 Paper in str1 array

The scanf family functions are known as a poor man's parser. They can easily parse blank separated tokens, but anything more complex is at best tricky, or even impossible - more exactly other tools should be used.
Your requirement is to accept in a single string any token until an integer token is found (token here being a blank delimited string). This is just not possible in single scanf.
If the type and number of blank characters does not matter, you could use a scanf loop first trying to find an integer, next getting tokens as string:
i = scanf("%d", &int1); // get first integer
if (i != 1) {
// error condition
}
char *cur = str1;
for(;;) {
if (1 == scanf("%d", &int2)) break; // ok we have found the second integer
i = scanf("%s", cur);
if (i != 1) {
// error condition
}
cur += strlen(cur); // move cur to end of string
*cur++ = ' '; // and add a space
}
if (cur != str1) {
cur[-1] = '\0'; // erase last space
}
This should detect read errors, but does not even try to control overflow of str1. It should be added for production grade code.

This is my solution
#include <stdio.h>
#include <string.h>
int main() {
int int1,int2;
char str[100],str1[81];
char *p;
scanf("%[^\n]s",str);
p = strtok (str," ");
sscanf(p, "%d", &int1);
p = strtok (NULL, " ");
strcpy(str1,p);
strcat(str1," ");
p = strtok (NULL, " ");
strcat(str1,p);
p = strtok (NULL, " ");
sscanf(p, "%d", &int2);
printf("%d %s %d",int1,str1,int2);
return 0;
}

Related

How to parse through a string of STDIN word by word in C

I would like to read standard input of a command and its argument in a C program, for instance:
ATTACK 50 30
I would like my program to parse through the input using whitespace and assign each word to a variable but right now I would just like to print each word. However, when I tried the program only returned ATTACK and not ATTACK 50 30.
I tried:
int main(){
// Grid size declaration //
int *x, *y;
char command[20];
char user_input[100];
scanf("%s", user_input);
printf("%s", user_input);
return 0;
}
As I said I used ATTACK 50 30 as my STDIN but my printf function only returned ATTACK. I thought of maybe using a while loop to keep scanning until the character interpreted is the return key (which I believe in this case would just be the null character?). I tried it using the code below:
int main(){
// Grid size declaration //
int *x, *y;
char command[20];
char user_input[100];
while(scanf("%s", user_input)!="\0"){
scanf("%s", user_input);
printf("%s", user_input);
}
return 0;
}
This did not work, the error produced declared I was comparing a pointer to an integer.
Since you are dealing with stdin it would probably be a better idea to utilize the fgets function in lieu of the scanf function, and then parse the inputted line of data utilizing the strtok string function.
Utilizing that strategy, following is a snippet of code allowing for the parsing of entered text where each word or data group is identified.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 64
int main()
{
char line[MAX + 1];
const char delim[2] = " ";
char * wd;
printf("Enter some text or type \"quit\" to end: ");
while (fgets(line, MAX, stdin))
{
line[strlen(line) - 1] = ' '; /* Replace newline character at the end with a space */
wd = strtok(line, delim);
while (wd != NULL)
{
if (strcmp(wd, "quit") == 0)
{
return 0;
}
printf("%s\n", wd);
wd = strtok(NULL, delim);
}
printf("Enter some text or type \"quit\" to end: ");
}
return 0;
}
Testing out this code utilizing your text example yielded the following terminal output.
#Dev:~/C_Programs/Console/ParseWord/bin/Release$ ./ParseWord
Enter some text or type "quit" to end: ATTACK 50 30
ATTACK
50
30
Enter some text or type "quit" to end: quit
#Dev:~/C_Programs/Console/ParseWord/bin/Release$
This is just a springboard from where you might go, but test that out and see if it meets the spirit of your project.

[C]: Segmentation fault using strcpy() into String Arrays

My assignment is to write a function that takes an input string from a user, tokenize it into several strings each containing an individual word from the input sentence, and then reverses the sentence. The result will be the sentence input but with the words in the reverse order.
For now, I just have the function taking in the input, tokenizing it into individual words, storing those words into an array, and printing out each individual word in order. I do not have the process for reversing the order of the words written yet.
Here is the code for the function i have handling this so far:
void reverse(void){
printf("\n\n%s\n", "Reverse words in String: ");
char input[200];
printf("\n%s", "Enter string\n> ");
scanf("%s", &input);
char reverseSentence[200];
char sentenceParts[20][200];
int wordCount = 0;
char *thisWord = strtok(input, " ");
strcpy(sentenceParts[wordCount], thisWord);
wordCount++;
while(thisWord != NULL){
thisWord = strtok(NULL, " ");
strcpy(sentenceParts[wordCount], thisWord);
wordCount++;
}
printf("\n\n");
for(int i = 0; i < wordCount + 1; ++i){
printf("%s%s", sentenceParts[i], " ");
}
}
The problem lies in the while statement:
while(thisWord != NULL){
thisWord = strtok(NULL, " ");
strcpy(sentenceParts[wordCount], thisWord);
wordCount++;
}
The program exits with a segmentation fault error at the strcpy statement. I cannot understand for the life of me why it is doing this. It seems like it worked just fine outside of the while loop.
Any thoughts? I've been stuck on this for quite a bit now and can't find too many other resources out there to help.
Updating thisWord with the next token should happen at the end of the loop body. As is, you'll eventually update thisWord with a NULL, and then call strcpy with a NULL. And that is your segfault.
So the loop should look like this:
char *thisWord = strtok(input, " ");
while(thisWord != NULL){
strcpy(sentenceParts[wordCount], thisWord);
wordCount++;
thisWord = strtok(NULL, " ");
}
The other problem (pointed out by #WhozCraig in the comments) is that you are inputting the line using scanf("%s", ...). That doesn't work because scanf will stop at the first whitespace character. Hence, you'll only get one word at a time from scanf. To get an entire line, use the fgets function.

How to print a word with specific character in C?

Sample Input: Stack Overflow is Awesome
Character to Search: e
Output: Overflow Awesome
I wrote a code to split a string by space and store as words but i don't know how to check and print the result
#include <stdio.h>
#include <string.h>
int main()
{
char str1[100];
char newString[10][10];
int i,j,ctr;
printf("\n\n Split string by space into words :\n");
printf("---------------------------------------\n");
printf(" Input a string : ");
fgets(str1, sizeof str1, stdin);
j=0; ctr=0;
for(i=0;i<=(strlen(str1));i++)
{
// if space or NULL found, assign NULL into newString[ctr]
if(str1[i]==' '||str1[i]=='\0')
{
newString[ctr][j]='\0';
ctr++; //for next word
j=0; //for next word, init index to 0
}
else
{
newString[ctr][j]=str1[i];
j++;
}
}
printf("\n Strings or words after split by space are :\n");
for(i=0;i < ctr;i++)
printf(" %s\n",newString[i]);
return 0;
}
You can use strchr() to easily check a string for a specific chararacter
for (i = 0; i < ctr; i++) {
if (strchr(newString[i], 'e') != NULL) {
printf(" %s\n", newString[i]);
}
}
Add the following lines at end to your code to print the filtered strings/words by character e
printf("\n Strings or words Containing character 'e' :\n");
for(i=0;i < ctr;i++)
if(strchr(newString[i], 'e') != NULL)
printf(" %s\n",newString[i]);
Since you are parsing str1 in order to find the beginning and the end of each word, why not using the for loop to detect if the current word contain the letter that you search ?
There are many little "error" too : do not use "strlen" in the for loop, it will be call each time ! Instead, detect '\0' !
Your result array newString is unsafe ! It should be [50][100] because you can input a string of one word with 100 char ( so [1][100] ) or 50 letter and 50 blank (so [50][2] ). So the result array must be [50][100] in order to take any possibility.
I would suggest to split the string using the strtok and using the strchr to check if the substring contains the letter e. In this way you can loop a single time over the original string and perform both the splitting and the checking.
Something like this:
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="Stack Overflow is Awesome";
char* pch;
char* pch2;
//split string by spaces
pch = strtok (str," ");
while (pch != NULL)
{
//check if the substring contains the letter 'e'
pch2 = strchr(pch,'e');
if (pch2 != NULL) {
printf ("%s\n",pch);
}
pch = strtok (NULL, " ");
}
return 0;
}

Why is strtok printing only first word?

I am using strtok for converting string into individual words. I have done the following:
int main() {
char target[100];
char *t;
scanf("%s",target);
t = strtok(target," ");
while (t!= NULL)
{
printf("<<%s>>\n", t);
t = strtok (NULL, " ");
}
return 0;
}
The input is a string such as 'this is a string', the output I am getting is<<this>>.
The way you have written scanf it will accept string till white space only
scanf("%s",target);
SO You need to change the way you take input from console
scanf("%99[^\n]",target);
Change:
scanf("%s",target);
to:
fgets(target, 100, stdin);
since the first won't stop when encounters the whitespace in your input.
Output:
this is a string
<<this>>
<<is>>
<<a>>
<<string
>>
Notice how the newline fgets() stores affects the output. You can simply discard it if you want, like this:
fgets(target, 100, stdin);
target[strlen(target) - 1] = '\0';
and now the output is:
this is a string
<<this>>
<<is>>
<<a>>
<<string>>
If you want to continue using scanf(), then you can use the below code snippet:
#include<stdio.h>
#include <string.h>
int main() {
char target[100];
char *t;
//scanf("%s",target);
scanf("%99[0-9a-zA-Z ]", target);
printf("%s\n",target);
t = strtok(target," ");
while (t!= NULL)
{
printf("<<%s>>\n", t);
t = strtok (NULL, " ");
}
return 0;
}
Working code here.
Just writing scanf("%s",target); will read the input only till the first white space; which is why you get only the first word as the output. By writing scanf("%99[0-9a-zA-Z ]", target);, you are reading 99 characters (including numbers 0-9, a-z or A-Z and white space) from the input stream.
Hope this is helpful.

Tokenizing a string

I am in the process of writing a C program that parses a string and tokenizing it by breaking the string characters into words that are seperated by white space. My question is when i run my current program:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char input[20];
printf("Please enter your word:\n");
scanf("%c", &input);
printf("%c", input[1]);
return 0;
}
If i was to enter the word "This", i would expect to get back "h" when i run the program but instead i get a downwards pointing arrow. However, when the input is set to print out input[0] i get back a "T".
Edit: I have modified my code so that it prints out the whole string now which i will show below
int main()
{
char input[20];
printf("Please enter your words:\n");
scanf("%s", input);
printf("%s", input);
return 0;
}
My goal is to be able to break that string into chars that i can search through to find whitespace and thus being able to isolate those words for example, if my input was "This is bad" i'd like the code to print out
This
is
bad
Edit:
I have modified my code to fit one of these answers but the problem i run into now is that it won't compile
int main()
{
char input[20];
printf("Please enter your words:\n");
size_t offset = 0;
do
{
scanf("%c", input + offset);
offset++;
}
while(offset < sizeof(input) && input[offset - 1] != '\n');
}
printf("%c", input[]);
return 0;
Problems:
1) scanf("%c", input); only set the first element of the array input.
2) printf("%c", input[1]); prints the second element of the array input, which has uninitialized data in it.
Solution:
Small state machine. No limit on string size like 20.
#include <ctype.h>
#include <stdio.h>
int main() {
int ch = fgetc(stdin);
while (ch != EOF) {
while (isspace(ch)) {
// If only 1 line of input allowed, then add
if (ch == '\n') return 0;;
ch = fgetc(stdin);
}
if (ch != EOF) {
do {
fputc(ch, stdout);
ch = fgetc(stdin);
} while (ch != EOF && !isspace(ch));
fputc('\n', stdout);
}
}
return 0;
}
scanf("%c", &input); does not do what you think it does.
First of all, %c scans only a single character: http://www.cplusplus.com/reference/cstdio/scanf/
Second, array's name is already a pointer to it's first element, so stating &input you make a pointer to a pointer, so instead of storing your character in array's first element you store it in pointer to the array which is a very bad thing.
If you really want to use scanf, I recommend a loop:
size_t offset = 0;
do
{
scanf("%c", input + offset);
offset++;
}
while(offset < sizeof(input) && input[offset - 1] != '\n');
Using scanf("%s", input") leaves you vulnerable to buffer overflow attacks if the word is longer than 20 characters http://en.wikipedia.org/wiki/Buffer_overflow
In my example I assumed, that you want to finish your word with a newline character.
EDIT: In scanf documentation is also a good example:
scanf("%19s", input);
It scans no more than 19 characters, which also prevent buffer overflow. But if you want to change input size, you have to change it two places.
You can use
char * strtok ( char * str, const char * delimiters );
to tokenize your string. If you have your input in input[] array and want to tokenize the string accoring to whitespace character, you can do the following :
char *ptr;
ptr = strtok(input, " ");
while(ptr != NULL) {
printf("%s\n", ptr);
ptr = strtok(NULL, " ");
}
Only the first call to strtok() requires the character array as input. Specifying NULL in the next calls means that it will operate on the same character array.
Your scanf only picks up the first character, input[1] contains random garbage. Use scanf("%19s", input) instead.

Resources