Segmentation fault: 11 while trying to parse string - c

I'm trying to parse an input string into a command string and an array of arguments strings.
I'm having some issue using strtok and strcpy, I think that my command string is not being null terminated properly which is leading to the seg fault.
#include <stdio.h>
#include <string.h>
#define delims " \t\r\n"
int main() {
char input[] = "ls -a -f";
char *buffer;
char command[256];
char arguments[256][256];
int i = 0, j;
buffer = strtok(input, delims);
strcpy(command, buffer);
printf("Command: %s\n\r", command);
while (buffer != NULL)
{
buffer = strtok(NULL, delims);
strcpy(arguments[++i], buffer);
}
buffer = strtok(NULL, delims);
for (j = 0; j < i; ++i)
{
printf("Argument[%d]: %s", j, arguments[j]);
}
return 0;
}
Current Output:
Command: ls
Segmentation fault: 11
Expected Output:
Command: ls
Argument[0]: -a
Argument[1]: -f
I don't pretend to be very good with C, so any pointers in the right direction would be extremely helpful.

Your problem likely revolves around the line strcpy(arguments[++i], buffer);. You are incrementing i, and then using it as an array index. The first round through the loop will copy into array index 1. When you print from the loop, you start at index 0. Since you don't initialize the arrays, they're full of garbage and bad things happen when you try to print index 0 (full of garbage) as a string.
Two suggestions to fix this: First, move expressions with side effects (like ++i) to a line of their own. This makes things simpler and eliminates any order-of-operations gotchas. Second, print out the arguments as soon as you read them instead of looping back through everything a second time. Since you're just printing the values, this would mean you wouldn't need an entire array to store all of the arguments. You'd only need enough buffer to store the current argument long enough to print it.

the following code:
compiles cleanly
removes unneeded local variables
outputs the proper items, then quits
defines magic numbers with meaningful names
uses NUL terminated array for the delimiters for strtok()
used the 'typical' name for the returned value of strtok()
always checks the returned value from strtok()
and now the code:
#include <stdio.h>
#include <string.h>
#define MAX_CMD_LEN (256)
#define MAX_ARGS (256)
#define MAX_ARG_LEN (256)
int main( void )
{
char input[] = "ls -a -f";
char *token;
char command[ MAX_CMD_LEN ] = {'\0'};
char arguments[ MAX_ARGS ][ MAX_ARG_LEN ] = {{'\0'}};
if ( NULL != (token = strtok(input, " \t\r\n" )) )
strcpy(command, token);
printf("Command: %s\n\r", command);
size_t i = 0;
while (i<MAX_ARGS && NULL != (token = strtok( NULL, " \t\r\n" ) ) )
{
strcpy(arguments[ i ], token);
i++;
}
for( i=0; *arguments[i]; i++ )
{
printf("Argument[%lu]: %s\n", i, arguments[i]);
}
return 0;
} // end function: main

Related

Spilting strings in C with mulitple delimiters [duplicate]

This question already has answers here:
split char string with multi-character delimiter in C
(5 answers)
Closed 1 year ago.
so i need to split the string given with:
const char *inputs[] = {"111adbhsd111gfhds","goal!","zhd!111oosd","111let111"};
to ouput:
char *outputs[]={"adbhsd","gfhds","goal!","zhd!","oosd","let"}
where the delimiter is : "111" .
I tried with strtok , but as the delimiter is of mulitple character , it did't work!
any idea, how it might give the output, will help!
what i have did till now:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
size_t split(
char **outputs, // outputs
const char *separator, // the delimiter
const char **inputs,
size_t num_inputs // no. of input strings, given in input array
){
size_t num_outputs = 0;
int l= 0;
for(size_t i = 0; i < num_inputs ; i++){
if(strstr(*(inputs+i), separator) != NULL){ // to check, if the string of the given input array has the delimiter
char* pos = strstr( *(inputs+i), separator);
//having problem in this part
}
else
{
strcpy( outputs[l] , *(inputs+i));;
l++;
num_outputs++;
}
}
return num_outputs;
}
int main(){
const char *inputs[] = {
"111abdhsd111gfhds",
"goal!",
"zhd!111oosd",
"111let111"
};
char *outputs[] ={malloc(1000),malloc(1000),malloc(1000),malloc(1000),malloc(1000),malloc(1000)};
split(outputs, "111", inputs, 4);
for(int i =0; i < 6; i++)
{
printf("The output[%d] is : %s" ,i, outputs[i]);
free(outputs[i]);
}
return 0;
}
NOTE: The following answer refers to revision 2 of the question, which is before OP added code to the question which already uses the function strstr.
If the string is delimited by a substring instead of a single character, you can use the function strstr to find the delimiter substrings:
#include <stdio.h>
#include <string.h>
int main( void )
{
const char input[] = "111adbhsd111gfhds", *p = input;
const char *const delim = "111";
//remember length of delimiter substring
const size_t delim_length = strlen( delim );
for (;;) //infinite loop, equivalent to "while ( 1 )"
{
//attempt to find next delimiter substring
const char *q = strstr( p, delim );
//break loop if this is last token
if ( q == NULL )
break;
//print token
if ( q == p )
printf( "Found token: <empty>\n" );
else
printf( "Found token: %.*s\n", (int)(q-p), p );
//make p point to start of next token
p = q + delim_length;
}
//print last token
printf( "Found token: %s\n", p );
}
This program has the following output:
Found token: <empty>
Found token: adbhsd
Found token: gfhds
Since the sample input starts with the delimiter "111", the first token is empty. If you don't want empty tokens to be printed, you can simply remove the first printf statement in the code.
This is not a full solution to your problem, as your task seems to consist of multiple input strings instead of only one, and writing to output arrays instead of printing to the screen. In accordance with the community guidelines for homework questions, I will not provide a full solution to your problem at this time. Instead, for now, I have only provided a solution to the problem that you stated that you had trouble with (which was using strtok with substring delimiters). If necessary, I can add additional code later.

Execvp() is not accepting 'ls' as Argument

#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";

how to save a string token , save its content to an array, then use those contents for further comparison

/*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.

How to make program end when specific line of redirected file is read

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.

Arrays in C not working

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 :-)

Resources