Ive been working on a c program that will allow the user to type in line of text until they type in the phrase "The end" on a line by itself. The program will replace every occurrence of "is" with the string "was" and count the number of changes made.
so far I've written some code but I'm getting a little lost on how to get it to work correctly, as of right now the program is giving me a buffer overflow error
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main ()
{
char str[500];// ="- This, a sample string.";
char * pch;
char endTerm[5000];
printf("Enter a string to parse: ");
scanf("%[^\n]",str);
strcat(endTerm, str);
while ( (strcmp(str, "the end")) != 0 || (strcmp(str, "the end.")) != 0 )
{
scanf("%[^\n]",str);
strcat(endTerm, str);
}
printf ("Your original string was: %s\n\n",endTerm);
pch = strtok (endTerm," ,-");
while (pch != NULL)
{
if ((strcmp(pch, "is")) == 0)
{
pch = "was";
}
else if ((strcmp(pch, "is.")) == 0)
{
pch="was.";
}
printf ("%s ",pch);
pch = strtok (NULL, " ,-");
}
printf("\n\n");
return 0;
}
I can probably figure out how to end the program if the user types the end, but i really need help with replacing the word is with was.
As others have pointed out in the comments above, there are several flaws in your program.
First flaw is your usage of strcat function. If you read the documentation, you would understand that strcat treats the first argument as a destination pointer and hence expects the user to allocate sufficient memory (enough to hold the concatenated string) to the destination pointer. In your case you are passing a string of " " which can accommodate only 1 character. This is the reason, you are getting the buffer overflow or segmentation fault.
The second error in your program is in the usage of strcmp function. This function returns 0 (which is defined by false and not true in strbool.h) when two strings are equal.
The third problem in your program is in the usage of the function strtok. You need to pass NULL as the first argument from the second call onward to get the pointers to the remaining tokens.
So fix these 3 errors first and then try to think about what else needs to be corrected in order to get your desired output.
Related
I`m having a hard time splitting a sentence read from a file in C programming language via strtok function. I scanned it from a file and stored it in a variable info, from which I need to separate words. I tried many things and eventually copied a code from the net and changed it a little bit. The code separates the first token nicely, but then it writes some nonsense.
#include <stdio.h>
#include <string.h>
void main()
{
//int i; //brojac
char info[]=""; // sve informacije, kasnije treba da bude u strukturi
FILE *pok;
pok=fopen("C:/Users/Trajkovici/Desktop/OsobeFajl.txt","r");
if(pok==NULL)
{
printf("Greška prilikom otvaranja datoteke!");
}
fscanf(pok,"%[^\n]",&info);
puts("INFO: ");
puts(info);
//fclose(pok);
char * token = strtok(info, " ");
// loop through the string to extract all other tokens
while( token != NULL )
{
puts("\nTOKEN:");
printf( " %s\n", token ); //printing each token
token = strtok(NULL, " ");
}
}
This is the file and the result:
The result
The file
BTW, I wrote the same code, without extracting a sentence from a file, but instead declaring it manually. It works perfectly fine.
#include<stdio.h>
#include <string.h>
int main() {
char string[] = "Sladjan Jankovic 46 Vranje";
// Extract the first token
puts(string);
char * token = strtok(string, " ");
// loop through the string to extract all other tokens
while( token != NULL )
{
printf( " %s\n", token ); //printing each token
token = strtok(NULL, " ");
}
return 0;
}
And this is the result of the above code:
The result
So, the problem is that I have two codes with literally same variables, but one of them splits into tokens fine, while the other one doesn`t. Any help about the first code?
P.S. Sorry for possible bad indentation, this is my first time posting on Stack Overflow. Also, some comments and lines from the file are in Serbian.
char info[]="";
will allocate only one element. Using it in
fscanf(pok,"%[^\n]",&info);
is dangerous because it will write out-of-bounds when a string with positive length is read. (even one-character string is too long because there must be a terminating null-character).
Allocate enough elements like (for example):
char info[102400]="";
and specify the maximum length to read (the limit have to be at most the size of buffer minus one for terminating null-character) to prevent buffer overrun like this:
fscanf(pok,"%102399[^\n]",info);
Also note that you should remove & before info. Arrays in expressions (except for some exceptions) are automatically converted to pointers for their first elements. Adding & will have it pass a pointer to an array while %[ expects a pointer to a character. Passing data having wrong type to fscanf() invokes undefined behavior.
I am having a struggle with the following exercise in my book:
Write a program that prompts the user to enter a series of words separated by single spaces, then prints the words in reverse order. Read the input as a string, and then use strtok to break it into words.
Input:hi there you are cool
Output: None it shuts itself.
Expected:cool are you there hi
My program only gets the string and waits and shuts after a couple of seconds. Here's the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void){
int ch ;
char * str , * str2;
char * p;
str = (char*)malloc(sizeof(char) * 100);
str2 =(char*)malloc(sizeof(char) * 100);
if((fgets(str , sizeof(str) , stdin)) != NULL){
str = strtok(str ," \t");
p = strrchr(str , '\0');
strcat(str2,p);
printf("%s",p);
while(str != NULL){
str = strtok(NULL ," \t");
p = strrchr(str + 1, '\0');
strcat(str2,p);
printf("%s",p);
}
}
return 0;
}
I know this question has been asked here. I get the idea there but my problem is implementation and carrying out. This is more of a beginner question.
Since you yourself stated that this is for an exercise I will not provide a working solution but an outline of what you might want to do.
Functions you want to use:
getline - for an easy read of an input line (notice that the newline character will not be eliminated
strtok_r to get the tokens (i.e. the words) from the input string
the _r means that this function is re-entrant which means that it can saftly be called by multiple threads at the same time. The normal version has an internal state and strtok_r lets you manage that state via a parameter.
(Please also read the docs for these functions if you have further questions)
For the algorithm:
Use getline to read a single line from input and replace the newline character with the 0 char. Then you should extract all one token after the other from the input and store them in a stack like fashion. After you tokenized the input just pop the token from the stack an print them to the stdout.
Another approach would be:
Write a function that simply reverses a string. Then use this function to reverse the input string and then for all tokens to read the token from the reversed input string and print the reverse token to stdout.
Currently learning C, Having some trouble with passing c-string tokens into array. Lines come in by standard input, strtok is used to split the line up, and I want to put each into an array properly. an EOF check is required for exiting the input stream. Here's what I have, set up so that it will print the tokens back to me (these tokens will be converted to ASCII in a different code segment, just trying to get this part to work first).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char string[1024]; //Initialize a char array of 1024 (input limit)
char *token;
char *token_arr[1024]; //array to store tokens.
char *out; //used
int count = 0;
while(fgets(string, 1023, stdin) != NULL) //Read lines from standard input until EOF is detected.
{
if (count == 0)
token = strtok(string, " \n"); //If first loop, Get the first token of current input
while (token != NULL) //read tokens into the array and increment the counter until all tokens are stored
{
token_arr[count] = token;
count++;
token = strtok(NULL, " \n");
}
}
for (int i = 0; i < count; i++)
printf("%s\n", token_arr[i]);
return 0;
}
this seems like proper logic to me, but then i'm still learning. The issue seems to be with streaming in multiple lines before sending the EOF signal with ctrl-D.
For example, given an input of:
this line will be fine
the program returns:
this
line
will
be
fine
But if given:
none of this
is going to work
It returns:
is going to work
ing to work
to work
any help is greatly appreciated. I'll keep working at it in the meantime.
There are a couple of issues here:
You never call token = strtok(string, " \n"); again once the string is "reset" to a new value, so strtok() still thinks it is tokenizing your original string.
strtok is returning pointers to "substrings" inside string. You are changing the contents of what is in string and so your second line effectively corrupts your first (since the original contents of string are overwritten).
To do what you want you need to either read each line into a different buffer or duplicate the strings returned by strtok (strdup() is one way - just remember to free() each copy...)
I'm trying to do split some strings by {white_space} symbol.
btw, there is a problem within some splits. which means, I want to split by {white_space} symbol but also quoted sub-strings.
example,
char *pch;
char str[] = "hello \"Stack Overflow\" good luck!";
pch = strtok(str," ");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok(NULL, " ");
}
This will give me
hello
"Stack
Overflow"
good
luck!
But What I want, as you know,
hello
Stack Overflow
good
luck!
Any suggestion or idea please?
You'll need to tokenize twice. The program flow you currently have is as follows:
1) Search for space
2) Print all characters prior to space
3) Search for next space
4) Print all characters between last space, and this one.
You'll need to start thinking in a different matter, two layers of tokenization.
Search for Quotation Mark
On odd-numbered strings, perform your original program (search for spaces)
On even-numbered strings, print blindly
In this case, even numbered strings are (ideally) within quotes. ab"cd"ef would result in ab being odd, cd being even... etc.
The other side, is remembering what you need to do, and what you're actually looking for (in regex) is "[a-zA-Z0-9 \t\n]*" or, [a-zA-Z0-9]+. That means the difference between the two options, are whether it's separated by quotes. So separate by quotes, and identify from there.
Try altering your strategy.
Look at non-white space things, then when you find quoted string you can put it in one string value.
So, you need a function that examines characters, between white space. When you find '"' you can change the rules and hoover everything up to a matching '"'. If this function returns a TOKEN value and a value (the string matched) then what calls it, can decide to do the correct output. Then you have written a tokeniser, and there actually exist tools to generate them called "lexers" as they are used widely, to implement programming languages/config files.
Assuming nextc reads next char from string, begun by firstc( str) :
for (firstc( str); ((c = nextc) != NULL;) {
if (isspace(c))
continue;
else if (c == '"')
return readQuote; /* Handle Quoted string */
else
return readWord; /* Terminated by space & '"' */
}
return EOS;
You'll need to define return values for EOS, QUOTE and WORD, and a way to get the text in each Quote or Word.
Here's the code that works... in C
The idea is that you first tokenize the quote, since that's a priority (if a string is inside the quotes than we don't tokenize it, we just print it). And for each of those tokenized strings, we tokenize within that string on the space character, but we do it for alternate strings, because alternate strings will be in and out of the quotes.
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
int main() {
char *pch1, *pch2, *save_ptr1, *save_ptr2;
char str[] = "hello \"Stack Overflow\" good luck!";
pch1 = strtok_r(str,"\"", &save_ptr1);
bool in = false;
while (pch1 != NULL) {
if(in) {
printf ("%s\n", pch1);
pch1 = strtok_r(NULL, "\"", &save_ptr1);
in = false;
continue;
}
pch2 = strtok_r(pch1, " ", &save_ptr2);
while (pch2 != NULL) {
printf ("%s\n",pch2);
pch2 = strtok_r(NULL, " ", &save_ptr2);
}
pch1 = strtok_r(NULL, "\"", &save_ptr1);
in = true;
}
}
References
Tokenizing multiple strings simultaneously
http://linux.die.net/man/3/strtok_r
http://www.cplusplus.com/reference/cstring/strtok/
I'm trying to port a software to Linux. It works greatly on Windows.
On Linux it gives me a segmentation fault on strcmp:
int main(void) {
...
char* comando;
char istruzione[100];
scanf("%[^\n]%*c", istruzione);
comando = strtok(istruzione, " ");
if (strcmp(comando, "fput") == 0)
...
}
The issue goes away using the array notation, but I need to use the * notation because I need to use strtok, which returns a * char.
strtok can return NULL, which means you need to check for that before using it in strcmp.
As a general rule in C, always check your return values, and always check that a pointer returned by a function is not NULL before attempting to do anything with it.
There's no telling what might have produced this segmentation fault without knowing the input to your program, but I would recommend very strongly that you avoid ever using scanf, which can produce segmentation faults or much worse. Here you could safely do this instead:
if (fgets(istruzione, 100, stdin) != NULL) {
comando = strtok(istruzione, " \n");
if (comando != NULL) {
if (strcmp(comando, "fput") == 0) {
....
The scanf call you are using reads one line of text without copying the newline character. fgets reads the newline character, but you can tell strtok to just treat it as another delimiter in order to ignore it.
Assuming, istruzione is a simple char buffer, I put together the following test. One thing I observed with what you had, was that if you just hit ENTER as the input for the scanf, doing the strcmp would cause a segmentation fault. This was because strtok returns NULL since there's nothing to tokenize.
You may need to test if strtok is returning a NULL pointer before using comando. You can see how I did this in the following test code.
scanf.c
#include <stdio.h>
#include <string.h>
char istruzione[256];
int main(void) {
char* comando;
scanf("%[^\n]%*c", istruzione);
comando = strtok(istruzione, " ");
/* test for NULL here */
if (NULL != comando)
{
if (strcmp(comando, "fput") == 0)
printf("%s\n", comando);
}
return 0;
}