Hi i'm struggling with understanding what's wrong with my program.
My best guess is something related with this line of code here:
scanf("%s", str);
The thing is i'm trying to call a function that uses a strtok on a String passed on to it typed by the user, all of this inside of a while loop as shown in the code example below:
int i = 0;
char str[80];
while(i != 3){
printf("Type in some string so i can break it: ");
scanf("%s", str);
testFunc(str);
printf("Loop %i ended.\n", i);
i++;
}
return 1;
Result (not what i want, see further below what i actually want):
Type in some string so i can break it: hey there how are you doing!
hey
Loop 0 ended.
Type in some string so i can break it:
there
Loop 1 ended.
Type in some string so i can break it:
how
Loop 2 ended.
The reason why i think this is caused by the scanf line is because the program works fine when i'm using instead some dummy pre-declared String
int i = 0;
while(i != 3){
char str[80] = "hey there how are you doing!";
testFunc(str);
printf("Loop %i ended.\n", i);
i++;
}
return 1;
Result:
hey
there
how
are
you
doing!
Loop 0 ended.
hey
there
how
are
you
doing!
Loop 1 ended.
hey
there
how
are
you
doing!
Loop 2 ended.
Here's the funtion that uses strtok, most of the code here is taken from https://www.tutorialspoint.com/c_standard_library/c_function_strtok.htm
int testFunc(char linha[80]){
//
const char s[2] = " ";
char *token;
/* get the first token */
token = strtok(linha, s);
/* walk through other tokens */
while(token != NULL) {
printf("%s\n", token);
token = strtok(NULL, s);
}
return 1;
}
I'm puzzled, it's like the program is executing testFunc() in paralel with the main function.
I think the problem is when you execute this loop:
while(i != 3){
printf("Type in some string so i can break it: ");
scanf("%s", str);
testFunc(str);
printf("Loop %i ended.\n", i);
i++;
}
scanf gets only one word at a time, so the loop cycles 3 times, you only get 3 words no matter how long the input string is.
On the other hand, in your other example you already have a string to break apart so the function will work.
There are different ways to get spaced strings from the console but here is what I consider to be a good option to do it:
str[MAX_SIZE];
fgets(str, MAX_SIZE, stdin);
// where MAX_SIZE is the maximum size you want to allow for the string,
//must be smaller than str.
According to scanf(3) man page:
Matches a sequence of non-white-space characters; the next
pointer must be a pointer to the initial element of a
character array that is long enough to hold the input sequence
and the terminating null byte ('\0'), which is added
automatically. The input string stops at white space or at
the maximum field width, whichever occurs first
You can use fgets or fread for input:
char buffer[1000];
/* fgets (reads a line of text with trailing newline */
fgets (buffer, 1000, stdin);
Related
I am building a find and replace program in C. it needs to be able to replace whatever is searched for in a text file with some thing else.
Eg. Search elo in input.txt replace with ELO
Result: developers devELOpers
eg search el replace EL hello hELlo welcome wELcome
I am having real trouble getting all the characters in a string before a pointer. I can get the single words and the pointer for the search word and i can get everything after the search term but i cannot get everything before the searched characters.
Tried strlen on the whole word and subtracting to no avail. I also can get the length of the first part of the word i need.
Thanks for any help.
search for era in
operating:
Outputs are
firstMatch= erating
End part =ting
startLength 2
#include <stdio.h>
#include<stdlib.h>
#include <string.h>
#define LINE_LENGTH 1000
//Function to remove a newline character and replace it with a null terminator.
void remove_newline(char *str)
{
int len =strlen (str);
if (len>0 &&str[len -1] == '\n')
str[len -1] = '0';
}
int main(int argc, char **argv)
{
char* searchWord = argv[1]; //Define the string searched for as argument 1.
char* replaceWord = ""; // Initialise the word for replacing search word.
char* text_File= ""; // Initialise the text file
for(int i = 0; i < argc; i++)
{
if (strcmp(argv[i],"-r")==0)
{
replaceWord = argv[i+1]; // Identify the replacemnt word as the argument that comes after "-r".
}
if (strcmp(argv[i],"-i")==0)
{
text_File = argv[i+1]; // Identify the file word as the argument that comes after "-i".
}
}
char slen= strlen(searchWord);
printf("You have searched for %s\n", searchWord); // Clarify for the user their search terms and input file.
printf("In the file %s\n", text_File);
FILE *input_file = fopen(text_File, "r"); // Open the text file
char line [LINE_LENGTH];
FILE *write_file = fopen("output.txt", "w"); //Create a new file for writing to.
` while (fgets(line, LINE_LENGTH, input_file) != NULL) ***// Loop through the contents of the input file.***
{
char *currentWord; ***// Separate the words at any of "\n ,.-".***
char *tempWord;
currentWord = strtok(line, "\n ,.-");
while (currentWord != NULL) ***// Loop through every seperated word.***
{
remove_newline(currentWord); //Remove the newline character form the current word.
if (strstr(currentWord, searchWord)!= NULL) ***// Check if the current word contains the searh word***
{
printf ("%s ", currentWord); ***// If it does print to console the word containing it***
char currLength= strlen(currentWord);
printf("%d\n", currLength);
char* firstMatch= strstr(currentWord, searchWord); ***// Find the first occurence of the searched term***
printf ("firstMatch %s\n ", firstMatch); ***//Print evrything after and including search.***
char* lastPart = firstMatch + slen; ***// Get the part after the search***
printf ("End part %s\n ", lastPart);
char rest = strlen(firstMatch);
char startLength = currLength - rest;
This is where it doesn't work.
char* startPart = firstMatch - startLength;
printf ("start Part %s\n ", startPart);
printf ("startLength %d\n\n ", startLength);`
The reason for the unexpected result when you try to print the "before the match" portion of the word is that there's nothing in the word string that will cause the
printf("start Part %s\n ", startPart);
call to stop after it has printed the first startLength characters of the word. When printf is told to print a string, it prints all characters from the starting point until it encounters a \0 terminator. Here, the only \0 is at the end of the word, so printf prints the entire word.
If you want to only print the first few characters of the word, you have to either construct a \0-terminated string that only contains those first few characters or you have to print them by using a mechanism that does not try to treat them as a string.
To construct a \0-terminated start string you could temporarily overwrite the first character of the match with a \0, then call printf, and then restore the match character. Something like:
char savedFirstMatch = *firstMatch;
*firstMatch = '\0';
printf("start Part %s\n ", startPart);
*firstMatch = savedFirstMatch;
If you don't want to do that then you could use a for loop to print only the first startLength characters as individual characters, not as a string, preceded and followed by a printf or puts that emits whatever extra stuff you want to print around those characters. In this case the extra stuff is a "start Part " string before the characters, and a newline and space afterwards (assuming that that space isn't just a typo). That would look something like:
puts("start Part ");
unsigned startIndex;
for (startIndex = 0; startIndex < startLength; ++startIndex) {
putchar(startPart[startIndex]);
}
puts("\n ");
Of course if you aren't comfortable with puts and putchar you can use printf("%s", ...) and printf("%c", ...) instead.
I have created a function that reverses all the words in a sentence, meaning that if the input is "Hello World" the output is supposed to be "World Hello". The code below is the function.
char* reversesentence(char sent[]) {
int lth = strlen(sent);
int i;
for(i = lth -1; i >= 0; i--) {
if(sent[i] == ' ') {
sent[i] = '\0';
printf("%s ", &(sent[i]) + 1);
}
}
printf("%s", sent);
}
In the main I am trying to ask the user for the sentence and calling the function in the main.
int main(void)
{
char sentence[2000];
printf("Please enter the sentence you want to be reversed.\n");
scanf("%s", sentence);
reversesentence(sentence);
printf("%s", sentence);
}
It seems that the array is only storing the first word of the sentence only.
Output:
Please enter the sentence you want to be reversed.
hello my name is
hellohello
Process finished with exit code 0`
Can someone help me fix this please? Searched online and found nothing useful.
scanf stops reading when it occurs whitespace,tabs or newline.
Matches a sequence of non-white-space characters; the next pointer
must be a pointer to character array that is long enough to hold the
input sequence and the terminating null byte ('\0'), which is added
automatically. The input string stops at white space or at the maximum
field width, whichever occurs first.
Thus you are not reading the entire string as you input.
Try using fgets as below.
fgets(sentence, sizeof(sentence), stdin);
Note fgets appends \n to end of the string. see how to trim the
new line from
fgets
You have two problems
as it was already said you only read one word using scanf
reversesentence just replace all spaces by a null character, so even you read a full line you cut it at the first space. so if you enter "hello world" the result will be "hello", and if you enter " hello world" the result will be an empty string
The simple way is to read words using scanf in a loop until it returns EOF, memorizing them, to at the end produce the list of words returned
For instance :
#include <stdlib.h>
#include <string.h>
int main()
{
size_t len = 0;
char * result = 0;
char word[256];
while (scanf("%256s", word) != EOF) {
if (result == 0) {
result = strdup(word);
len = strlen(word);
}
else {
size_t l = strlen(word);
char * r = malloc(len + l + 2);
strcpy(r, word);
r[l] = ' ';
strcpy(r + l + 1, result);
free(result);
result = r;
len += l + 1;
}
}
puts(result);
free(result);
return 0;
}
The reading finishes at the end of the input (^d under a linux shell), the words can be given on several lines.
With the input
hello world
how
are you
?
that prints
? you are how world hello
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
What I want to do is to input two words in C but one word can be omitted sometimes.
To be more precise there is exactly one word necessarily and the other number of words may vary. which can be zero ,one , two or three
As an example sometimes the input can be
Hello world
while sometimes it can be just
Hello
the reason why i want this to be done is I'm taking inputs in a while loop
(I have to take input continuously and process according to them)
I have used
"%s %[^\n]%*c"
but it waits until I enter another word. (Because its expecting a another word after space)
I tried googling and all the aspects of scanf but didn't find any solution.
Any help appreciated ! Thanks...
This is a case where not using scanf() is astonishingly simple:
char line[1024];
while (fgets(line, 1024, stdin))
{
char *word = strtok(line, " \t\n");
while (word)
{
// do something with word
word = strtok(0, " \t\n"); // <- next word
}
}
As for scanf() and how/why not to use it, I suggest reading my beginners' guide away from scanf().
Side note: strtok() isn't thread-safe. If this is a concern, there are alternatives like the POSIX strtok_r() or the C11 strtok_s(). Beware Microsoft also has a strtok_s() which is different from the standard C version.
scanf() does not seem to be the right tool for your purpose, you should instead read one line at a time with fgets() and process it according to the words that are present.
If you insist on using scanf(), "%s %[^\n]%*c" does not work because the space matches newlines. Assuming array sizes of 20 bytes, you could use "%19[^ \t\n]%*[ \t]%19[^ \t\n]" and check the return value to see how many words have been read on a single line (0, 1, 2 or EOF), but if you expect a variable number of words, fgets() is a much preferred solution.
Here is an example for up to 3 words per line:
int scan_input(void) {
char word1[20], word2[20], word3[20];
int n, c;
for (;;) {
switch (n = scanf("%19[^ \t\n]%*[ \t]%19[^ \t\n]%*[ \t]%19[^ \t\n]",
word1, word2, word3)) {
case EOF:
return EOF;
case 0:
/* no word on the line, skip the empty line */
break;
case 1:
/* one word on the line */
printf("1 word: %s\n", word1);
break;
case 2:
/* two word on the line */
printf("2 words: %s %s\n", word1, word2);
break;
case 3:
/* three word on the line */
printf("3 words: %s %s\n", word1, word2, word3);
break;
}
/* ignore the rest of the line */
while ((c = getchar()) != EOF && c != '\n')
continue;
}
}
Here is an example using fgets():
int scan_input(void) {
char buf[256];
int n, pos, len;
while (fgets(buf, sizeof buf, stdin)) {
/* scan the line, skipping whitespace */
for (n = 1, pos = 0; buf[pos += strspn(buf, " \t\n")] != '\0'; n++) {
/* compute the word length */
len = strcspn(buf + pos, " \t\n");
/* found word at offset `pos` of length `len` bytes */
printf("word %d: %.*s\n", n, len, buf + pos);
pos += len;
}
}
return EOF;
}
It is not a problem if you want omit one word sometimes. But i would recommend you not using scanf()use fgets()instead and process your string after you have read it.
Syntax
char chr[MAX];
while(i<10){
fgets(chr,MAX, stdin);
}
If you want to omit your second word, just check for a whitespace in your string and terminate it on that place/index the String with \0.
I agree with the others that scanf() is probably not the right tool here.
Another way could be to use fgets() and strchr() and a pointer as in
char str[100], *ptr;
while( (fgets(str, sizeof(str), stdin))!=NULL ){
if( (ptr=strchr(str, '\n'))!=NULL )
{
*ptr=0;
}
if( (ptr=strchr(str, ' '))!=NULL )
{
*ptr=0;
ptr++;
if( strchr(ptr, ' ')==NULL )
{
printf("\nTwo words: %s, %s", str, ptr);
}
else
{
printf("\nMore than two words!");
}
}
else//only one word
{
printf("\nOne word: %s", str);
}
}
fgets() is used to read in the input into a character array str. fgets() returns NULL on error.
Since fgets() also reads in any trailing \n, we check the string for \n if it's there, it's replaced with a \0 to denote end of string in the
if( (ptr=strchr(str, '\n'))!=NULL )
{
*ptr=0;
}
part.
strchr() returns NULL if the searched character is not present in the string.
strchr() is again used to check for a space in str. If none is found, only one word was read and otherwise multiple words were input.
If more than one word is there, the space is replaced with a \0 using the pointer returned by strchr() so that doing a
printf("%s", str);
will now print only the first word and the pointer is incremented so that it now points to the beginning of the second word. This is done in
if( (ptr=strchr(str, ' '))!=NULL )
{
*ptr=0;
ptr++;
Now, strchr() is once again used to check for another case in which case more than two words were input. Otherwise only two words were input and the second word is output using
printf("%s", ptr);
You could use a similar approach to read more words.
This program essentially asks for a secret string, then asks a user to repeatedly guess single chars of that string until he guesses it all. It works however every second time the while loop is run it skips user input for the guessed char. How do I fix this?
int main(){
char guess;
char test2 [50];
char * s = test2;
char output [50];
char * t = output;
printf("Enter the secret string:\n");
fgets(test2, 50, stdin);
for (int i=0;i<49;i++){ //fills ouput with _ spaces
*(output +i)='_';
while(strcmp(s,t) != 0){
printf("Enter a guess:");
scanf("%c",&guess);
printf("You entered: %c\n", guess);
showGuess(guess,s, t ); // makes a string "output" with guesses in it
printf("%s\n",t);
}
printf("Well Done!");
}
For a quick and dirty solution try
// the space in the format string consumes optional spaces, tabs, enters
if (scanf(" %c", &guess) != 1) /* error */;
For a better solution redo your code to use fgets() and then parse the input.
As pointed out in some other answers and comments, you need to "consume" the "newline character" in the input.
The reason for that is that the input from your keyboard to the program is buffered by your shell, and so, the program won't see anything until you actually tell your shell to "pass the content of its buffer to the program". At this point, the program will be able to read the data contained in the previous buffer, e.g. your input, followed by one the character(s) used to validate your input in the shell: the newline. If you don't "consume" the newline before you do another scanf, that second scanf will read the newline character, resulting in the "skipped scanf" you've witnessed. To consume the extra character(s) from the input, the best way is to read them and discard what you read (what the code below does, notice the
while(getc(stdin) != '\n');
line after your scanf. What this line does is: "while the character read from stdin is not '\n', do nothing and loop.").
As an alternative, you could tell your shell to not buffer the input, via the termios(3) functions, or you could use either of the curses/ncurses libraries for the I/O.
So here is what you want:
int main(){
char guess;
char test2 [50];
char * s = test2; // 3. Useless
char output [50];
char * t = output; // 3. Useless
int i; // 8. i shall be declared here.
printf("Enter the secret string:\n");
fgets(test2, 50, stdin);
for (i=0;i<50;i++) if (test2[i] == '\n') test2[i] = '\0'; // 4. Remove the newline char and terminate the string where the newline char is.
for (int i=0;i<49;i++){ // 5. You should use memset here; 8. You should not declare 'i' here.
*(output +i)='_';
} // 1. Either you close the block here, or you don't open one for just one line.
output[49] = '\0'; // 6. You need to terminate your output string.
while(strcmp(s,t) != 0){ // 7. That will never work in the current state.
printf("Enter a guess:");
scanf("%c",&guess);
while(getc(stdin) != '\n');
printf("You entered: %c\n", guess);
showGuess(guess,s, t );
printf("%s\n",t);
}
printf("Well Done!");
return 0; // 2. int main requires that.
}
Other comments on your code:
You opened a block after your for loop and never closed it. That might be causing problems.
You declared your main as a function returning an integer... So you should at least return 0; at the end.
You seem to have understood that char * t = output; copies output's value and uses t as a name for the new copy. This is wrong. You are indeed copying something, but you only copy the address (a.k.a reference) of output in t. As a result, output and t refer to the same data, and if you modify output, t will get modified; and vice versa. Otherwise said, those t and s variables are useless in the current state.
You also need to remove the newline character from your input in the test2 buffer. I have added a line after the fgets for that.
Instead of setting all the bytes of an array "by hand", please consider using the memset function instead.
You need to actually terminate the output string after you "fill" it, so you should allocate a '\0' in last position.
You will never be able to compare the test2 string with the output one, since the output one is filled with underscores, when your test2 is NULL terminated after its meaningful content.
While variables at the loop scope are valid according to C99 and C11, they are not standard in ANSI C; and it is usually better to not declare any variable in a loop.
Also, "_ spaces" are called "underscores" ;)
Here is a code that does what you want:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 50
int main()
{
char phrase[LEN];
char guessed[LEN];
char guess;
int i, tries = 0;
puts("Please enter the secret string:");
if(fgets(phrase, LEN, stdin) == NULL)
return 1;
for(i = 0; i < LEN && phrase[i] != '\n'; i++); // Detect the end of input data.
for(; i < LEN; i++) // For the rest of the input data,
phrase[i] = '_'; // fill with underscores (so it can be compared with 'guessed' in the while loop).
phrase[LEN - 1] = '\0'; // NULL terminate 'phrase'
memset(guessed, '_', LEN); // Fill 'guessed' with underscores.
guessed[LEN - 1] = '\0'; // NULL terminate 'guessed'
while(strcmp(phrase, guessed) != 0) // While 'phrase' and 'guessed' differ
{
puts("Enter a guess (one character only):");
if(scanf("%c", &guess) != 1)
{
puts("Error while parsing stdin.");
continue;
}
if(guess == '\n')
{
puts("Invalid input.");
continue;
}
while(getc(stdin) != '\n'); // "Eat" the extra remaining characters in the input.
printf("You entered: %c\n", guess);
for(i = 0; i < LEN; i++) // For the total size,
if(phrase[i] == guess) // if guess is found in 'phrase'
guessed[i] = guess; // set the same letters in 'guessed'
printf("Guessed so far: %s\n", guessed);
tries++;
}
printf("Well played! (%d tries)\n", tries);
return 0;
}
Feel free to ask questions in the comments, if you are not getting something. :)
Newline character entered in the previous iteration is being read by scanf. You can take in the '\n' by using the getc() as follows:
scanf("%c",&guess);
getc(stdin);
..
This changed worked for me. Though the right explanation and c leaner code is the one given by #7heo.tk
Change
scanf("%c",&guess);
with
scanf(" %c",&guess);
It should ignore '\n'.
I have written code for parsing a string into words. Here is code. Can any one help here to fix the segmentation fault error during run time?
Calling fun :
int main()
{
int count = 0, i; // count to hold numbr of words in the string line.
char buf[MAX_LENTHS]; // buffer to hold the string
char *options[MAX_ORGS]; // options to hold the words that we got after parsing.
printf("enter string");
scanf("%s",buf);
count = parser(buf,options); // calling parser
for(i = 0; i < count; ++i)
printf("option %d is %s", i, options[i]);
return 0;
}
Called function:
int parser(char str[], char *orgs[])
{
char temp[1000];//(char *)malloc(strlen(str)*sizeof(char));
int list = 0;
strcpy(temp, str);
*orgs[list]=strtok(str, " \t ");
while(((*orgs[list++]=strtok(str," \t"))!=NULL)&&MAX_ORGS>list)
list++;
printf("count =%d",list);
return list;
}
Note : I'm trying to learn C these days, can any one help to get a good tutorial (pdf) or site to learn these strings with pointers, and sending string to functions as arguments?
You are using strtok wrong.
(It is generally best to not use strtok at all, for all its problems and pitfalls.)
If you must use it, the proper way to use strtok is to call it ONCE with the string you want to "tokenize",
then call it again and again with NULL as an indication to continue parsing the original string.
I also think you're using the orgs array wrong.
Change this assignment
*orgs[list++]=strtok(str, " \t ");
to this:
orgs[list++]=strtok(str, " \t ");
Because orgs is an array of character-pointers.
orgs[x] is a character-pointer, which matches the return-type of strtok
Instead, you are referring to *orgs[x], which is just a character.
So you are trying to do:
[character] = [character-pointer];
which will result in "very-bad-thingsā¢".
Finally, note that you are incrementing list twice each time through your loop.
So basically you're only filling in the even-elements, leaving the odd-elements of orgs uninitialized.
Only increment list once per loop.
Basically, you want this:
orgs[list++] = strtok(str, " \t ");
while(( (orgs[list++] = strtok(NULL," \t")) !=NULL) && MAX_ORGS > list)
/* do nothing */;
PS You allocate space for temp, and strcpy into it.
But then it looks like you never use it. Explain what temp is for, or remove it.
char buf[MAX_LENTHS];
You have not defined the array size, i. e. MAX_LENTHS should be defined like
#define MAX_LENTHS 25
And as Paul R says in his comment you also need to initialize your array of character pointers
char *options[MAX_ORGS];
with something .
int parser(char str[], char *orgs[]){
int list=0;
orgs[list]=strtok(str, " \t\n");
while(orgs[list]!=NULL && ++list < MAX_ORGS)
orgs[list]=strtok(NULL," \t\n");
printf("count = %d\n",list);
return list;
}
int main(){
int count=0,i;
char buf[MAX_LENTHS];
char *options[MAX_ORGS];
printf("enter string: ");
fgets(buf, sizeof(buf), stdin);//input include space character
count=parser(buf,options);
for(i=0;i<count;++i)
printf("option %d is %s\n",i,options[i]);
return 0;
}