Well, I declared a global array of chars like this char * strarr[];
in a method I am tokenising a line and try to put everything into that array like this
*line = strtok(s, " ");
while (line != NULL) {
*line = strtok(NULL, " ");
}
seems like this is not working.. How can I fix it?
Thanks
Any number of things could be going wrong with the code you haven't shown us, such as undefined behaviour by strtoking a string constatnt, or getting your parameters wrong when calling the function.
But the most likely problem from the code we can see is the use of *line instead of line, assuming that line is of type char *.
Use the following code as a baseline:
#include <stdio.h>
#include <string.h>
int main (void) {
char str[] = "My name is paxdiablo";
// Start tokenising words.
char *line = strtok (str, " ");
while (line != NULL) {
// Print current token and get next word.
printf ("[%s]\n", line);
line = strtok(NULL, " ");
}
return 0;
}
This outputs:
[My]
[name]
[is]
[paxdiablo]
and should be easily modifiable into something you can use.
Be aware that, if you're trying to save the character pointers returned from strtok (which would make sense for using *line), they are transitory and will not be what you expect after you're done. That's because modifications are made in-place within the source string. You can do it with something like:
#include <stdio.h>
#include <string.h>
int main (void) {
char *word[4]; // The array of words.
size_t i; // General counter.
size_t nextword = 0; // For preventing array overflow.
char str[] = "My name is paxdiablo";
// Start tokenising.
char *line = strtok (str, " ");
while (line != NULL) {
// If array not full, duplicate string to array and advance index.
if (nextword < sizeof(word) / sizeof(*word))
word[nextword++] = strdup (line);
// Get next word.
line = strtok(NULL, " ");
}
// Print out all stored words.
for (i = 0; i < nextword; i++)
printf ("[%s]\n", word[i]);
return 0;
}
Note the specific size of the word array in that code above. The use of char * strarr[] in your code, along with the message tentative array definition assumed to have one element is almost certainly where the problem lies.
If your implementation doesn't come with a strdup, you can get a reasonably-priced one here :-)
Related
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#define MAX_LIMIT 20
int main () {
printf("Shell> ");
char str1[MAX_LIMIT];
fgets(str1, MAX_LIMIT, stdin);
char delim[] =" ";
char *parsed;
int index = 0;
char *cmd[index];
parsed = strtok(str1,delim);
while( parsed != NULL) {
cmd[index] = parsed;
index++;
parsed = strtok(NULL, delim);
}
cmd[index] = NULL;
int wow = fork();
if(wow == 0){
execvp((char*)cmd[0],cmd);
}
return(0);
}
Everything above is working fine except execvp()
cmd[0] receives string 'ls', technically execvp() should display the list but it doesn't.
If I replace cmd[0] with 'ls', it works.
You have two main issues here.
First when you declare your array as char *cmd[index];, the size of the array is not tied to current value of index as index changes. It sets the size to the current value of index which is 0. Creating an array of size 0 invokes undefined behavior. You need to set a fixed size for the array that will be big enough for your needs.
char *cmd[MAX_LIMIT];
The other problem is your choice of delimiters. The fgets function reads a line of text including the newline at the end of the input. So whichever parameter is read last will have a \n at the end of it. To fix this, add \n to the delimiter list.
char delim[] =" \n";
/*I am unsure if my code for saving the tokens in an array is accurate.
This is so because been whenever I run my program, the code to compare
token[0] with my variable doesn't give an output nor perform assigned function.
Hence I am sure there is something inaccurate about my coding.*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
//variable declarations
const char *array[] = {"ax","bo","cf"};
char delim[]=" \n";
char* myline;
size_t max = 500;
char* token1;
char* token2[max];
int n = 0;
while(1) //loop always
{
printf("Enter an argument\n"); //asks for an input
getline (&myline, &max, stdin); //read the input/line
//for loop -- splits up the line into tokens
for(token1 = strtok(myline, " "); token1 != NULL; token1 = strtok(NULL, delim))
{
token2[n] = malloc(strlen(token1)+1); //allocate some space/memory to token2[n]
//save the token in an array by copying from token1 to token2
strcpy(token2[n],token1);
int m;
for(m = 0; m<sizeof(array);m++) //loop through the array elements for comparison
{
//compare array at index m with token at index 0 -- compare only first token with a specific variable
if(strcmp(token2[0], array[m]) == 0)
{
printf("equal");
}
}
}
free(token2[n]); //deallocate assigned memory
}
return(0);
}
I think you should try vector of string like
vector < string > str = { "ax","bo","cf" };
Their seems to be a few issues in your current code:
for(m = 0; m<strlen;m++) is not correct. strlen() is a <string.h> function used to obtain the length of a C string. Since you want array[i], you need to include the size of array in the guard. To find the size of the array, you can use sizeof(array)/sizeof(array[0]). It would be good to include this in a macro:
#define ARRAYSIZE(x) (sizeof x/sizeof x[0])
Then your loop can be:
size_t m;
for(m = 0; m<ARRAYSIZE(array); m++)
You need to check return of malloc(), as it can return NULL on failure to allocate spaces. Here is a way to check this:
token2[n] = malloc(strlen(token1)+1);
if (token2[n] == NULL) {
/* handle error */
It is possible to skip the malloc()/strcpy() step by simply using strdup.
getline() returns -1 on failure to read a line, so its good to check this. It also adds a \n character at the end of the buffer, so you need to remove this. Otherwise, strcmp will never find equal strings, as you will be comparing strcmp("string\n", "string"). You need to find the \n character in your buffer, and replace it with a \0 null-terminator.
You can achieve this like:
size_t slen = strlen(myline);
if (slen > 0 && myline[slen-1] == '\n') {
myline[slen-1] = '\0';
}
You also need to free() all of the char* pointers in token2[].
Since you are using the same delimeter for strtok(), its better to make this const. So const char *delim = " \n"; instead.
Alot of the fixes I suggested in the comments, so I didn't post them here, as you seemed to have updated your code with those suggestions.
Ok, so I'm going to explain my program.
It takes a text file that's setup as such: in pairs, first line being the title of an experiment, and the second line being 10 numbers separated by spaces. It saves the first lines of pairs in *experiments and the second lines of pairs in data. The last line is *** END *** which is what it's supposed to end with.
For some reason *** END *** doesn't end the program. Any ways I can fix this? I'm assuming it's because fgets gives str blank spaces (99 chars total) so that the string in quotes will never be equal to str?
Thanks.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int var;
int i=0,j,k;
char seps[] = " ";
char *experiments[20];
int data[10][20];
char str[100]; // make sure that this size is enough to hold the single line
char *ptr, *token;
int no_line=1;
while(fgets(str,100,stdin) != NULL && strcmp(str,"*** END ***"))
{
if(no_line % 2 == 0)
{
k=0;
token = strtok (str, seps);
while (token != NULL)
{
sscanf (token, "%d", &var);
data[i][k++] = var;
token = strtok (NULL, seps);
}
i++;
/*read integer values from the string "str" using sscanf, sscanf can be called in a loop with %d untill it fails */
}
else
{
ptr = strdup(str);
experiments[i] = ptr;
/*strore string in your variable "experiments" , before copying allocate a memory for the each entry */
}
no_line++;
}
for(j=0;j<i;j++)
{
printf("%s",experiments[j]);
for(k=0;k<10;k++)
{
printf("%d ",data[j][k]);
}
printf("\n");
}
}
You're declaring i here ...
int i,j,k;
... and using it here ...
data[i][k++] = var;
Nowhere do you initialize i. Also, why does data need to be a 2D array? Can't it just be a 1D array?
int data[10];
...
data[k++] = var;
From this code, int i seems to be declared, but not initialized?
data[i][k++] = var;
It may be helpful to use Eclipse or Code Block IDE to try small testable codes because it has all sorts of syntax and error checking features.
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.
What I am trying to do is to break the user input in parts with whitespace as a delimiter, copy the parts into the array (tokenAr) and compare the tokenAr[0] (the first part) if it is equal to sHistory. if they are equal, check the value of tokenAr[1] if it is "1", "2" etc, to execute the corresponding command that is entered in the history array. This is what i have tried to far and it crashes. I am using TCC on Windows x64.
EDIT: I forgot to mention that I began learning C, just two days ago.
EDIT2: I run the program in a debugger and it has raised an Acces Violation(Segmentation Fault) in line if(strcmp(tokenArPtr[0],sHistory)==0)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int i=1; int j=1; int k=0;
char history[100][100] = {0};
char sKey[] = "exit";
char sInput[100];
char sHistory[]="history";
do
{
//gather user input
printf ("hshell> ");
fgets (sInput, 100, stdin);
strcpy(history[i],sInput);
i++;
//END_gather user input
//Tokenizing
char delims[] = " ";
char *tokenArPtr[5];
char *result = NULL;
result = strtok(sInput, delims);
tokenArPtr[0] = result;
while (result!=NULL)
{
puts(result);
result= strtok(NULL, delims);
tokenArPtr[k+1] = result;
puts(tokenArPtr[k]);
puts("=====");
k++;
}
k=0;
/*
//END_Tokenizing
if(strcmp(tokenArPtr[0],sHistory)==0)
{
for(j=1;j<i;j++)
{
printf("%d. %s \n",j,history[j]);
}
}
else if (strcmp (sKey,tokenArPtr[0]) != 0)
{
printf("\nCommand not found \n");
}*/
}while (strcmp (sKey,sInput) != 0);
return 0;
}
EDIT 3: I used the result variable instead of the tokenArPtr directly, but when debugging, I noticed that the values of the array are not being updated.
Which type does strtok return? char *. What is the type of tokenAr[k]? char. What type does strcmp expect as input? char * and char *. What is the type of tokenAr[0]? char.
See a problem? You should. The * is pretty significant.
Assuming tokenAr is declared like char *tokenAr[2];, how many char * values can tokenAr store? What happens when k exceeds 2? You need to ensure you don't overflow your tokenAr array.
history is uninitialised. Using an uninitialised variable is undefined behaviour. I suggest initialising it, like this: char history[100][100] = { 0 };
Which book are you reading?
While tokenizing, the loop will never end because the test is on the variable "result" that will never change... So you're finally going to a buffer overflow with "tokenAr"... Modify your code to test "tokenAr".
Edit: And tokenAR should be an array... (I don't know how it can compile...)
There are many problems... First of all you should include string.h which will show you some errors in compilation.
I believe that the main problem is here:
char tokenAr[2];
result = strtok(sInput, delims);
while (result!=NULL)
{
tokenAr[k] = strtok(NULL, delims);
k++;
}
tokenAr should be an array of pointers, not chars. And are you sure that k will never exceed 2? An assertion would help debugging.