I want to split the first command line argument into two different numbers. I got a segmentation fault error when running the program this way:
gcc -ansi main.c -o main
./main 6000V7000
Here is the source code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *token;
char arr[200];
strcpy(arr, argv[1]);
token = strtok(arr, "v,V");
int firstNumber = atoi(token);
token = strtok(NULL, "v,V");
int secondNumber = atoi(token);
return 0;
}
How can I fix this problem?
You do not test if there is at least one command line argument, nor that this argument is less than 200 characters long, nor do you test the return values of strtok: you would have undefined behavior if the command is given no argument or if the argument does not contain any of the characters v, V or ,.
If you effectively compile the program with gcc -ansi main.c -o main and run it with the posted argument as ./main 6000V7000 you should not get a segmentation fault... There is something you are not telling us ;)
It is always better to avoid wild assumptions: test for the unexpected to give your program defined behavior in all cases.
Here is a simpler approach for your problem using sscanf():
#include <stdio.h>
int main(int argc, char *argv[]) {
int a, b;
if (argc > 1 && sscanf(argv[1], "%d%*1[vV,]%d", &a, &b) == 2)
printf("a=%d, b=%d\n", a, b);
return 0;
}
The code and command line arguments given do not seg-fault. However if the command line argument either omits the delimiter, includes a space before the second number, or omits any argument at all, then it will fail.
The following will prevent erroneous input causing a runtime error:
if( argc > 1 )
{
strcpy( arr, argv[1]);
int firstNumber = 0 ;
int secondNumber = 0 ;
token = strtok(arr, "v,V");
if( token != NULL )
{
firstNumber = atoi(token) ;
token = strtok(NULL, "v,V") ;
if( token != NULL )
{
secondNumber= atoi(token);
}
}
}
You must define var at the begin of the function :
The follow code could work :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]){
char *token;
char arr[200];
int firstNumber;
int secondNumber;
strcpy( arr, argv[1]);
token = strtok(arr, "v,V");
firstNumber = atoi(token);
token = strtok(NULL, "v,V");
secondNumber= atoi(token);
return 0;
}
There's only one "V" in your input. The second call to strtok() finds no V and returns NULL.
Related
I'm trying to build a version of a linux shell wherein, I take in the commands from the user and execute the commands using execv() system call.
I'm using strtok_r to tokenize the commands and pass the arguments to execv(). For example, when the user types in the command "ls -l", I first remove the leading/trailing white spaces and then tokenize the command into two tokens 1) ls, 2) -l. I concatenate the first token with a char path[10] in which I've already copied "/bin/" path. So, after concatenation, path becomes "/bin/ls". However, the execv() call fails. But, when I directly pass "/bin/ls" (instead of passing it as a variable) as the argument in execv(), it works. Code is shown below:
Please let me know where I've committed the mistake.
`
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>
void removeTrailingLeadingSpaces(char* stringInput);
int main ()
{
printf("dash> ");
char* input;
size_t characters;
size_t bufsize = 32;
input = (char *)malloc(bufsize*sizeof(char));
characters = getline(&input,&bufsize,stdin);
removeTrailingLeadingSpaces(input);
char *args[2];
char* last;
char* token;
token = strtok_r(input," ",&last);
printf("%s\n", token);
removeTrailingLeadingSpaces(token);
char path[10];
strcpy(path,"/bin/");
strcat(path,token);
args[0] = path;
printf("%s\n",args[0]);
args[1] = strtok_r(NULL," ",&last);
args[2] = NULL;
int i = access(args[0],X_OK);
printf("result is %d",i);
int j= execv(args[0],args);
printf("result2 is %d",j);
return 0;
}
void removeTrailingLeadingSpaces(char* input)
{
while(isspace((unsigned char)*input))
input++;
int i=strlen(input)-1;
while(i>0)
{
if(input[i] == ' '|| input[i] == '\n'|| input[i] =='\t')
i--;
else
break;
}
input[i+1] = '\0';
}
`
I am trying to make a function that reads a text file which contains data and assign it to a variable. However some lines start with $ which need to be ignored. For example:
$ Monday test results
10 12
$ Tuesday test results
4
This is what I have so far which just prints out:
10 12
4
The code that does this is:
#include <stdio.h>
#include <stdlib.h>
void read_data(){
FILE* f;
if (f = fopen("testdata.txt", "r")) {
char line[100];
while (!feof(f)) {
fgets(line, 100, f);
if (line[0] == '$') {
continue;
} else{
puts(line);
}
}
} else {
exit(1);
}
fclose(f);
}
void main(){
read_data();
return 0;
}
I have tried fgetc and have googled extensively but am still stuck ;(
**Edits
Added #include and main
What I am asking is how to assign like a = 10, b = 12, c = 4. Had troubles since using fgets is for lines. Tried fgetc but it would only ignore the actual $ sign not the whole line that the $ is on
C string.h library function - strtok()
char *strtok(char *str, const char *delim)
str − The contents of this string are modified and broken into smaller strings (tokens).
delim − This is the C string containing the delimiters. These may vary from one call to another.
This function returns a pointer to the first token found in the string. A null pointer is returned if there are no tokens left to retrieve.
Copied from: https://www.tutorialspoint.com/c_standard_library/c_function_strtok.htm
#include <string.h>
#include <stdio.h>
int main () {
char str[80] = "This is - www.tutorialspoint.com - website";
const char s[2] = "-";
char *token;
/* get the first token */
token = strtok(str, s);
/* walk through other tokens */
while( token != NULL ) {
printf( " %s\n", token );
token = strtok(NULL, s);
}
return(0);
}
Output:
This is
www.tutorialspoint.com
website
this is my first question on stack and I'm beginner in c.I declared a char array a[100]={"this is a test\n2nd test}.Now I'm trying to divide this array and take the two parts before and after \n as separate strings.So I declared a 2d array ab[i][k] and used a for loop to copy the characters to ab[i]. if a[j]=='\n' , I put a NULL character at the current position of ab[i][k] and increment i by 1.But for some reason, both ab[0] and ab[1] are displaying "this is a test" when I used printf to display them.Any help or suggestions would be appreciated.
int i=0;
char a[100],ab[100][100],c;
fputs(a,stdout);
printf("%d ",strlen(a));
for(j=0;j<=strlen(a);j++,k++)
{
if(a[j]=='\n')
{
ab[i][k]='\0';
k=0;
i++;
continue;
}
ab[i][k]=a[j];
}
printf("%s\n",ab[0]);
printf("%s",ab[1]);
You need to set k=-1; when you find \n, since it will be incremented at the top of the loop to 0 when you continue;.
You also need to declare int j, k=0; before the loop, to get your code to compile.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[]) {
int i=0;
char ab[100][100];
char a[100] = "this is a test\n2nd test";
printf("%d \n",strlen(a));
int j, k=0;
for(j=0; j<=strlen(a); j++,k++) {
if(a[j]=='\n') {
ab[i][k]='\0';
k=-1;
i++;
continue;
}
ab[i][k]=a[j];
}
printf("1: %s\n",ab[0]);
printf("2: %s\n",ab[1]);
return 0;
}
23
1: this is a test
2: 2nd test
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
char ar[100] = "this is a test\n2nd test\nfoobar\netc";
char sep[10][100];
int i=0;
char* token = strtok(ar, "\r\n");
while(token != NULL) {
sprintf(sep[i], "%s", token);
printf("string #%02i: `%s`.\n", i, sep[i]);
token = strtok(NULL, "\r\n");
i++;
}
return 0;
}
strtok() splits a string by any of the characters passed as a delimiter (new line and carriage return, in this case) into tokens. Passing a null pointer to the function continues where it last left off. It returns a pointer to the beginning of the token,
sprintf() saves formatted data into a variable handling \0 for you, but you could also use memcpy() or strcpy() if you like.
I have a string containing datatypes and addresses of variables. These values are separated by "///" and they are alternating (type /// address /// type /// address ...). The amount of these tuples is not fixed and can vary from execution to execution.
Now my problem is how to process the string in a loop, as strtok needs to be called first with the original string and then with the NULL parameter but in the loop it has to be called twice. So after the first loop strtok is called three times which leads to an uneven count of strtok executions whereas it should be an even count. I tried to solve this problem by processing the first tuple outside the loop (because strtok has to be called with the original string) and process the remaining tuples inside the loop.
char mystring[128];
char seperator[] = "///";
char *part;
int type [128];
int address [128];
number_of_variables = 0;
part = strtok(mystring, seperator);
type[number_of_variables] = (int) atoi(part);
part = strtok(NULL, seperator);
address[number_of_variables] = (int)strtol(part, NULL, 16);
while(part != NULL){
part = strtok(NULL, seperator);
type[number_of_variables] = (int) atoi(part);
part = strtok(NULL, seperator);
address[number_of_variables] = (int)strtol(part, NULL, 16);
number_of_variables++;
}
So now I have an even count of strtok executions but if my strings contains for example 2 tuples it will enter the loop for a second time so strtok is called for a fifth time which causes the program to crash as atoi() gets a bad pointer.
EDIT:
Example for mystring:
"1///0x37660///2///0x38398"
1 and 2 are type identifiers for the further program.
I can suggest the following loop as it is shown in the demonstrative program below.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
char mystring[128] = "1///0x37660///2///0x38398";
char separator[] = "/ ";
int type [128];
int address [128];
size_t number_of_variables = 0;
for ( char *part = strtok( mystring, separator ); part; part = strtok( NULL, separator ) )
{
type[number_of_variables] = atoi(part);
part = strtok( NULL, separator );
address[number_of_variables] = part ? (int)strtol(part, NULL, 16) : 0;
++number_of_variables;
}
for ( size_t i = 0; i < number_of_variables; i++ )
{
printf( "%d\t%x\n", type[i], address[i] );
}
return 0;
}
The program output is
1 37660
2 38398
You can write a robust and fast parser, that is guaranteed to work and has no bugs like this
File: lexer.l
%{
#include <stdio.h>
#include "parser.tab.h"
int yyerror(const char *const message);
%}
%option noyywrap
%x IN_ADDRESS
DECIMAL [0-9]+
HEX "0x"[a-fA-F0-9]+
DELIMITER "///"
%%
<*>{DELIMITER} { return DELIMITER; }
<INITIAL>{DECIMAL} {
char *endptr;
// Make the lexer know that we are expecting a
// hex number
BEGIN(IN_ADDRESS);
// Asign the value to use by bison
yylval = strtol(yytext, &endptr, 10);
// Check conversion's success
if (*endptr != '\0')
return ERROR;
return TYPE;
}
<IN_ADDRESS>{HEX} {
char *endptr;
// Restore the initial state
BEGIN(INITIAL);
// Asign the value to use by bison
yylval = strtol(yytext, &endptr, 16);
// Check conversion's success
if (*endptr != '\0')
return ERROR;
return ADDRESS;
}
%%
File: parser.y
%{
#include <stdio.h>
extern int yylex();
extern FILE *yyin;
int yyerror(const char *const message);
#define YYSTYPE int
%}
%token TYPE
%token DELIMITER
%token ADDRESS
%token ERROR
%%
program:
| program statement
;
command: TYPE DELIMITER ADDRESS {
fprintf(stdout, "type %d, address 0x%08x\n", $1, $3);
}
;
statement: command
| statement DELIMITER command;
;
%%
int
yyerror(const char *const message)
{
return fprintf(stdout, "error: %s\n", message);
}
int
main(void)
{
yyin = fopen("program.txt", "r");
if (yyin == NULL)
return -1;
yyparse();
}
File: program.txt
1///0x37660///2///0x38398
Compiling this with gcc, bison and flex is rather simple
bison -d parser.y
flex lexer.l
gcc -Wno-unused-function -Wall -Werror lex.yy.c parser.tab.c -o parserparser
Of course, this program needs some tweaking and adjusting it to your needs should be straightforward.
Just find a simple tutorial on bison and flex to help you fully understand this code.
While I am aware there are libraries for config file parsing I have tried to write my own implementation. The problem is that I can find the config option but comparing the string before the delimeter failes when I try to compare it with the thing I am searching for. I need to comare it with the thing I am searching for becasue my program allows things like Test2 and Test3 because it cannot check if there are characters before or after the word Test. The compare allways failes and I cannot figure out why.
Here is my code:
Main.c
#include <stdio.h>
#include <stdlib.h>
void Parser(char *CONFIG_FILE, int *P_VALUE, char *STRING_TO_LOOK_FOR);
int main(){
int VALUE;
Parser("config.txt", &VALUE, "Test");
printf("%d \n", VALUE);
}
Parser.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void Parser(char *CONFIG_FILE, int *P_VALUE, char *STRING_TO_LOOK_FOR){
FILE *FP=fopen(CONFIG_FILE,"a+");
char TMP[256]={0x0};
int i = 1;
while(FP!=NULL && fgets(TMP, sizeof(TMP), FP)!=NULL){ //Loop through every line
i=i+1; //Increment the line number
if (strstr(TMP, STRING_TO_LOOK_FOR)){ //Is the term im looking for in this line
char *NAME_OF_CONFIG_STR = strtok(TMP, "= "); //look for delimiter
char *STRVALUE = strtok(NULL, "= "); //Get everything past the delimiter
char *P_PTR;
char *pos;
if ((pos=strchr(NAME_OF_CONFIG_STR, '\n')) != NULL){ //attempt remove \n doesn't work
*pos = '\0';
}
if(strcmp(STRING_TO_LOOK_FOR, NAME_OF_CONFIG_STR) == 0){ //try to check the two are the same
*P_VALUE = strtol(STRVALUE, &P_PTR, 10); //Returns an integer to main of the value
}
}
}
if(FP != NULL){
fclose(FP);
}
}
config.txt:
Test= 1234
Test2= 5678
Test3= 9012
Thanks to BLUEPIXY and the demo they created this problem has been solved. The issue was in the gcc comiler options I had forgotten -std=99 somehow this caused the program to behave correctly.