I am trying to run the following code, but during execution, the code does not go into the if condition.
Why does the code not enter the if condition during runtime? I have marked the problem condition.
Running this program on Windows 10.
Thread model: posix
gcc version 5.1.0 (tdm64-1)
I have tried using the ternary operator and the if statement with a different string, and strchr works fine in that case.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void main() {
static char str[] = "hello world";
static char inputTime[] = "12:05:10PM";
char *result = strchr(str, 'w');
long int tempNum = 0;
char *token, tempStr[10], delimit[] = ":";
if (strchr(str, 'w'))
printf("\nFound w");
else
printf("\nDid not find w");
(strchr(inputTime, 'P')) ? printf("\nTrue") : printf("\nFalse");
token = strtok(inputTime, delimit);
if (strchr(inputTime, 'P')) {
printf("Found PM\n");
tempNum = strtol(token, NULL, 10);
if (tempNum != 12)
tempNum += 12;
sprintf(tempStr, "%lu", tempNum);
}
printf("\ntempStr: %s", tempStr);
}
The above code gives me this output:
C:\Users\XX\Documents\Tests\c-programming>a.exe
Found w
True
tempStr: σ#
The strtok function splits the given input string into tokens. It does this by modifying the string to tokenize, placing a null byte in place of the delimiter to search for.
So after the call to strtok, inputTime looks like this:
{ '1','2','\0','0','5',':','1','0','P','M','\0' }
A null byte is put in place of the first :. So if you were to print inputTime you would get 12, meaning you won't find a P.
Because the input string is modified, you should search for P before calling strtok.
Related
Say I have char ch[] = "/user/dir1/file.txt";
I want to use a loop such that:
1st iteration:
prints: "user"
2nd iteration:
prints: "dir1"
3rd iteration:
prints: "file1.txt"
reach the end of string. Exists the loop
You have to use strtok or its threadsafe version if you are developing a multithreaded program:
#include<stdio.h>
#include <string.h>
int main() {
char ch[] = "/user/dir1/file.txt";
// Extract the first token
char * token = strtok(ch, "/");
// loop through the string to extract all other tokens
while( token != NULL ) {
printf( "%s\n", token ); //printing each token
token = strtok(NULL, " ");
}
return 0;
}
A "simple", portable, thread-safe solution that does not modify the string, as the approach using strtok() does. So the approach below can be applied to literals as well!
#include <stdio.h>
#include <string.h>
int main(void)
{
const char * s = "/user/dir1/file.txt";
for (const char * ps = s, *pe;
pe = strchr(ps, '/'), ps != pe ?printf("%.*s\n", (int) (pe - ps), ps) :0, pe;
ps = pe + 1);
}
The only limitation this code is facing, is that the tokens within the string to be parsed may not be longer then INT_MAX characters.
I'm a beginner at C and I'm stuck on a simple problem. Here it goes:
I have a string formatted like this: "first1:second1\nsecond2\nfirst3:second3" ... and so on.
As you can see from the the example the first field is optional ([firstx:]secondx).
I need to get a resulting string which contains only the second field. Like this: "second1\nsecond2\nsecond3".
I did some research here on stack (string splitting in C) and I found that there are two main functions in C for string splitting: strtok (obsolete) and strsep.
I tried to write the code using both functions (plus strdup) without success. Most of the time I get some unpredictable result.
Better ideas?
Thanks in advance
EDIT:
This was my first try
int main(int argc, char** argv){
char * stri = "ciao:come\nva\nquialla:grande\n";
char * strcopy = strdup(stri); // since strsep and strtok both modify the input string
char * token;
while((token = strsep(&strcopy, "\n"))){
if(token[0] != '\0'){ // I don't want the last match of '\n'
char * sub_copy = strdup(token);
char * sub_token = strtok(sub_copy, ":");
sub_token = strtok(NULL, ":");
if(sub_token[0] != '\0'){
printf("%s\n", sub_token);
}
}
free(sub_copy);
}
free(strcopy);
}
Expected output: "come", "si", "grande"
Here's a solution with strcspn:
#include <stdio.h>
#include <string.h>
int main(void) {
const char *str = "ciao:come\nva\nquialla:grande\n";
const char *p = str;
while (*p) {
size_t n = strcspn(p, ":\n");
if (p[n] == ':') {
p += n + 1;
n = strcspn(p , "\n");
}
if (p[n] == '\n') {
n++;
}
fwrite(p, 1, n, stdout);
p += n;
}
return 0;
}
We compute the size of the initial segment not containing : or \n. If it's followed by a :, we skip over it and get the next segment that doesn't contain \n.
If it's followed by \n, we include the newline character in the segment. Then we just need to output the current segment and update p to continue processing the rest of the string in the same way.
We stop when *p is '\0', i.e. when the end of the string is reached.
Can I use the strstr function to match exact word? For example, let's say I have the word hello, and an input string line:
if
char* line = "hellodarkness my old friend";
and I use
result = strstr(line, "hello");
result will match (be not NULL), however I want to match only the exact word "hello" (so that "hellodarkness" would not match) and result will be NULL.
Is it possible to do this using strstr or do I have to use fscan and scan the line word by word and check for matches?
Here is a generic function for your purpose. It returns a pointer to the first match or NULL if none can be found:
#include <ctype.h>
#include <string.h>
char *word_find(const char *str, const char *word) {
const char *p = NULL;
size_t len = strlen(word);
if (len > 0) {
for (p = str; (p = strstr(p, word)) != NULL; p++) {
if (p == str || !isalnum((unsigned char)p[-1])) {
if (!isalnum((unsigned char)p[len]))
break; /* we have a match! */
p += len; /* next match is at least len+1 bytes away */
}
}
}
return p;
}
I would:
check if string is in sentence
if found at start (same pointer as line), add the length of the word and check if alphanumerical char found. If not (or null-terminated), then match
if found anywhere else, add the extra "no alphanum before" test
code:
#include <stdio.h>
#include <strings.h>
#include <ctype.h>
int main()
{
const char* line = "hellodarkness my old friend";
const char *word_to_find = "hello";
char* p = strstr(line,word_to_find);
if ((p==line) || (p!=NULL && !isalnum((unsigned char)p[-1])))
{
p += strlen(word_to_find);
if (!isalnum((unsigned char)*p))
{
printf("Match\n");
}
}
return 0;
}
here it doesn't print anything, but insert a punctuation/space before/after or terminate the string after "hello" and you'll get a match. Also, you won't get a match by inserting alphanum chars before hello.
EDIT: the above code is nice when there's only 1 "hello" but fails to find the second "hello" in "hellohello hello". So we have to insert a loop to look for the word or NULL, advancing p each time, like this:
#include <stdio.h>
#include <strings.h>
#include <ctype.h>
int main()
{
const char* line = " hellohello hello darkness my old friend";
const char *word_to_find = "hello";
const char* p = line;
for(;;)
{
p = strstr(p,word_to_find);
if (p == NULL) break;
if ((p==line) || !isalnum((unsigned char)p[-1]))
{
p += strlen(word_to_find);
if (!isalnum((unsigned char)*p))
{
printf("Match\n");
break; // found, quit
}
}
// substring was found, but no word match, move by 1 char and retry
p+=1;
}
return 0;
}
Since strstr() returns the pointer to the starting location of the substring that you want to identify, then you can use strlen(result) the check if it is a substring of longer string or the isolated string that you are looking for. if strlen(result) == strlen("hello"), then it ends correctly. If it ends with a space or punctuation (or some other delimiter), then it is also isolated at the end. You would also need to check if the start of the substring is at the beginning of the "long string" or preceded by a blank, punctuation, or other delimiter.
I tried using strncmp but it only works if I give it a specific number of bytes I want to extract.
char line[256] = This "is" an example. //I want to extract "is"
char line[256] = This is "also" an example. // I want to extract "also"
char line[256] = This is the final "example". // I want to extract "example"
char substring[256]
How would I extract all the elements in between the ""? and put it in the variable substring?
Note: I edited this answer after I realized that as written the code would cause a problem as strtok doesn't like to operate on const char* variables. This was more an artifact of how I wrote the example than a problem with the underlying principle - but apparently it deserved a double downvote. So I fixed it.
The following works (tested on Mac OS 10.7 using gcc):
#include <stdio.h>
#include <string.h>
int main(void) {
const char* lineConst = "This \"is\" an example"; // the "input string"
char line[256]; // where we will put a copy of the input
char *subString; // the "result"
strcpy(line, lineConst);
subString = strtok(line,"\""); // find the first double quote
subString=strtok(NULL,"\""); // find the second double quote
printf("the thing in between quotes is '%s'\n", subString);
}
Here is how it works: strtok looks for "delimiters" (second argument) - in this case, the first ". Internally, it knows "how far it got", and if you call it again with NULL as the first argument (instead of a char*), it will start again from there. Thus, on the second call it returns "exactly the string between the first and second double quote". Which is what you wanted.
Warning: strtok typically replaces delimiters with '\0' as it "eats" the input. You must therefore count on your input string getting modified by this approach. If that is not acceptable you have to make a local copy first. In essence I do that in the above when I copy the string constant to a variable. It would be cleaner to do this with a call to line=malloc(strlen(lineConst)+1); and a free(line); afterwards - but if you intend to wrap this inside a function you have to consider that the return value has to remain valid after the function returns... Because strtok returns a pointer to the right place inside the string, it doesn't make a copy of the token. Passing a pointer to the space where you want the result to end up, and creating that space inside the function (with the correct size), then copying the result into it, would be the right thing to do. All this is quite subtle. Let me know if this is not clear!
if you want to do it with no library support...
void extract_between_quotes(char* s, char* dest)
{
int in_quotes = 0;
*dest = 0;
while(*s != 0)
{
if(in_quotes)
{
if(*s == '"') return;
dest[0]=*s;
dest[1]=0;
dest++;
}
else if(*s == '"') in_quotes=1;
s++;
}
}
then call it
extract_between_quotes(line, substring);
#include <string.h>
...
substring[0] = '\0';
const char *start = strchr(line, '"') + 1;
strncat(substring, start, strcspn(start, "\""));
Bounds and error checking omitted. Avoid strtok because it has side effects.
Here is a long way to do this: Assuming string to be extracted will be in quotation marks
(Fixed for error check suggested by kieth in comments below)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char input[100];
char extract[100];
int i=0,j=0,k=0,endFlag=0;
printf("Input string: ");
fgets(input,sizeof(input),stdin);
input[strlen(input)-1] = '\0';
for(i=0;i<strlen(input);i++){
if(input[i] == '"'){
j =i+1;
while(input[j]!='"'){
if(input[j] == '\0'){
endFlag++;
break;
}
extract[k] = input[j];
k++;
j++;
}
}
}
extract[k] = '\0';
if(endFlag==1){
printf("1.Your code only had one quotation mark.\n");
printf("2.So the code extracted everything after that quotation mark\n");
printf("3.To make sure buffer overflow doesn't happen in this case:\n");
printf("4.Modify the extract buffer size to be the same as input buffer size\n");
printf("\nextracted string: %s\n",extract);
}else{
printf("Extract = %s\n",extract);
}
return 0;
}
Output(1):
$ ./test
Input string: extract "this" from this string
Extract = this
Output(2):
$ ./test
Input string: Another example to extract "this gibberish" from this string
Extract = this gibberish
Output(3):(Error check suggested by Kieth)
$ ./test
Input string: are you "happy now Kieth ?
1.Your code only had one quotation mark.
2.So the code extracted everything after that quotation mark
3.To make sure buffer overflow doesn't happen in this case:
4.Modify the extract buffer size to be the same as input buffer size
extracted string: happy now Kieth ?
--------------------------------------------------------------------------------------------------------------------------------
Although not asked for it -- The following code extracts multiple words from input string as long as they are in quotation marks:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char input[100];
char extract[50];
int i=0,j=0,k=0,endFlag=0;
printf("Input string: ");
fgets(input,sizeof(input),stdin);
input[strlen(input)-1] = '\0';
for(i=0;i<strlen(input);i++){
if(input[i] == '"'){
if(endFlag==0){
j =i+1;
while(input[j]!='"'){
extract[k] = input[j];
k++;
j++;
}
endFlag = 1;
}else{
endFlag =0;
}
//break;
}
}
extract[k] = '\0';
printf("Extract = %s\n",extract);
return 0;
}
Output:
$ ./test
Input string: extract "multiple" words "from" this "string"
Extract = multiplefromstring
Have you tried looking at the strchr function? You should be able to call that function twice to get pointers to the first and second instances of the " character and use a combination of memcpy and pointer arithmetic to get what you want.
I was trying to write a calculator program and so part of this I need to evaluate an expression.
So I need to perform the operation based on the operator given. I am taking the whole expression into a string.
For example it might be 5+6 or 5*6.
So I have written it in this way:
char input1[20] = "";
char input2[20] = "";
char output[20] = "";
char *arg1= NULL, *arg2 = NULL;
int value;
getinput ( input1); //Function for getting the expression
strcpy (input2, input1);
if ( arg1 = strtok (input1, "*"))
{
arg2 = strtok (NULL, "");
value = atoi(arg1) * atoi(arg2);
}
else
{
char* arg1, *arg2;
arg1 = strtok ( input2, "+");
arg2 = strtok ( NULL, "");
value = atoi (arg1) + atoi(arg2);
}
sprintf (output,"%d", value);
printf ("The output value is %s", output);
This code works only if I give expression having multiplication. For example it works only if I give 5*6. This is not working if I give 5+6.
The problem is in the else part. It is not able to tokenize the string input2.
Can't I tokenize two different strings in a single program.
Where am I wrong? Can someone explain me this concept of why strtok is not working for secong string?
the first strtok will not return NULL for "3+5", but rather a pointer to the token "3+5"
(so the else statement won't get executed).
now the problem is that the second call to strtok (around line #12 in your code) will return NULL, and the subsequent call atoi(NULL) will segfault.
The first strtok call will not return NULL (unless your input string is either empty or only contains '*' characters), so the else statement will not be executed for a string like "5+6".
You probably want to use strchr (or similar) to figure out what operation is to be performed, and then get the operands.
case of input "3+5" result of strtok(input1, "*") is "3+5", That else clause is not executed because it should not be NULL.
Second parameter for strtok is an array use like this strtok (input1, "+*"). That means that it will tokenize if they get '*' or '+'.
I code this like below:
#include <string.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
char ss[100] = "123+321";
int a = atoi(ss);
int aLength = (int)floor(log10((double)a))+1;
int b = atoi(ss+aLength);
if(ss[aLength] == '+')
printf("%d + %d = %d\n", a, b, (a+b));
else
printf("%d * %d = %d\n", a, b, (a*b));
return 0;
}