$ ./Main a
int main(int argc, char * argv[]) {
int i;
for(i=1;i<argc;i++){
if(argv[i] == NULL){ //This line does not work!
argv[i] = "Null";
}
}
theMenu(argv[1], argv[2], argv[3], argv[4]);
return (EXIT_SUCCESS);}
In theMenu function,when I called strcmp(argv[2],argv[3]); I will have segmentation fault :((
How can I make argv[x] = "Null" when user did not enter the parameter at x?
The CRT will not insert NULL entries for arguments you didn't receive. It will simply reduce the value of argc instead. If you must have four arguments, then you can define your own array on the stack.
int main(int argc, char * argv[]) {
char* args[4] = { 0 };
int i;
for(i=1;i<argc && i < 4;i++){
args[i] = argv[i];
}
for(int i = 0; i < 4; i++) {
if (args[i] == NULL)
args[i] = "Null";
}
theMenu(argv[1], argv[2], argv[3], argv[4]);
return (EXIT_SUCCESS);
}
You can't. What you can do is define your own array of size [4] initialized to empty strings or NULLs and copy arguments (up to argc count) there.
Your problem is that argc<5 and so you are attempting to access elements of argv that are not defined.
You're expecting 4 arguments. Why not trap it like so:
if (argc==5)
{
//code here
}
(it is 5 because there is an arg[0] when you run your code)
Related
In C programming language, is it possible to access int argc or char **argv without using the parameters? I know some of you might ask why this is needed, just for research purposes.
Is it possible to generate the cmd line arguments without using the main parameter variables ? For example, to illustrate some pseudo code, that i have in mind,
LPTSTR cmd = GetCommandLine();
splitted = cmd.split(" ") //split from spaces
char **someArgv.pushForEach Splitted, length++
and you'd have a someArgv with the parameters and length as argc, this'd really help to know if possible to illustrate.
If OP already has the command as a string, then:
Form a copy of the string
Parse it for argument count
Allocate for argv[]
Parse & tokenize copy for each argv[]
Call main()
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
// Not standard, but commonly available
char *strdup(const char *s);
// Return length of token and adjust offset to the next one
// Adjust as needed
// Presently only ' ' are used to separate
// More advanced would have escape characters, other white-space, etc.
size_t tokenize(const char *s, size_t *offset) {
// find following space
size_t len = strcspn(s + *offset, " ");
*offset += len;
// find first non-space
*offset += strspn(s + *offset, " ");
return len;
}
int call_main(const char *cmd) {
char *cmd2 = strdup(cmd);
cmd2 += strspn(cmd2, " "); // skip leading spaces
size_t offset = 0;
int argc = 0;
while (tokenize(cmd2, &offset) > 0) {
argc++;
}
char **argv = malloc(sizeof *argv * ((unsigned)argc + 1u));
offset = 0;
for (int a = 0; a < argc; a++) {
argv[a] = &cmd2[offset];
size_t len = tokenize(cmd2, &offset);
argv[a][len] = '\0';
}
argv[argc] = NULL;
int retval = 0;
#if 0
retval = main(argc, argv);
#else
printf("argc:%d argv:", argc);
for (int a = 0; a < argc; a++) {
printf("%p \"%s\", ", argv[a], argv[a]);
}
printf("%p\n", argv[argc]);
#endif
free(cmd2);
free(argv);
return retval;
}
Sample
int main() {
call_main(" name 123 abc 456 ");
}
argc:4 argv:0x800062322 "name", 0x800062327 "123", 0x80006232c "abc", 0x800062331 "456", 0x0
Pedantic: The strings provided to main() should be modifiable. Avoid code like
argv[1] = "Hello";
....
main(argc, argv);
#include <stdio.h>
int main(int argc, char *argv[]);
int callMain(void)
{
char *argv[4];
argv[0] = "binary";
argv[1] = "param1";
argv[2] = "param2";
argv[3] = NULL;
return main(3, argv);
}
int main(int argc, char *argv[])
{
if (argc <= 1)
{
return callMain();
}
printf("ARGC: %u\n", argc);
int i;
for (i = 0; i < argc; i++)
printf("ARG: %u - %s\n", i, argv[i]);
return 0;
}
I've written the code, however I cannot remember how to get the user's input.
The command to run the code is ./rle "HHEELLLLO W" but in my code, I don't know how to get the code to read the "HHEELLLLO W".
If I have a regular printf function, the code will work and will print H1E1L3O 0W0 but I want it so any user's input can be calculated.
I tried using atoi but I think I've done it wrong and I don't know how to fix it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_RLEN 50
char* encode(char* src)
{
int rLen;
char count[MAX_RLEN];
int len = strlen(src);
char* dest = (char*)malloc(sizeof(char) * (len * 2 + 1));
int i, j = 0, k;
for (i = 0; i < len; i++) {
dest[j++] = src[i];
rLen = 1;
while (i + 1 < len && src[i] == src[i + 1]) {
rLen++;
i++;
}
sprintf(count, "%d", rLen);
for (k = 0; *(count + k); k++, j++) {
dest[j] = count[k];
}
}
dest[j] = '\0';
return dest;
}
int main(int argc, char ** argv)
{
char str[] = atoi(argv[1]);
char* res = encode(str);
printf("%s", res);
getchar();
}
When I compile it, I get this error:
rle.c: In function ‘main’:
rle.c:47:18: error: invalid initializer
char str[] = atoi(argv[1]);
^~~~
rle.c:45:14: error: unused parameter ‘argc’ [-Werror=unused-parameter]
int main(int argc, char ** argv)
^~~~
cc1: all warnings being treated as errors
atoi converts strings (of digits) to integers, which is nothing like what you to do here.
I would recommend doing this one of two ways:
(1) Use the command-line argument directly:
int main(int argc, char ** argv)
{
char* str = argv[1];
char* res = encode(str);
printf("%s\n", res);
}
This works because argv[1] is already a string, as you want. (In fact in this case you don't even need str; you could just do char* res = encode(argv[1]);.)
In this case you will have the issue that the shell will break the command line up into words as argv[1], argv[2], etc., so argv[1] will contain just the first word. You can either use quotes on the command line to force everything into argv[1], or use the next technique.
(2) Read a line from the user:
int main(int argc, char ** argv)
{
char str[100];
printf("type a string:\n");
fgets(str, sizeof(str), stdin);
char* res = encode(str);
printf("%s\n", res);
}
In both cases there's also some additional error checking you theoretically ought to do.
In the first case you're assuming the user actually gave you a command-line argument. If the user runs your program without providing an argument, argv[1] will be a null pointer, and your code will probably crash. To prevent that, you could add the test
if(argc <= 1) {
printf("You didn't type anything!\n");
exit(1);
}
At the same time you could double-check that there aren't any extra arguments:
if(argc > 2) {
printf("(warning: extra argument(s) ignored)\n");
}
In the second case, where you prompt the user, there's still the chance that they won't type anything, so you should check the return value from fgets:
if(fgets(str, sizeof(str), stdin) == NULL) {
printf("You didn't type anything!\n");
exit(1);
}
As you'll notice if you try this, there's also the issue that fgets leaves the \n in the buffer, which may not be what you want.
I've been trying to figure out what I'm doing wrong in this block of code for a while now and still no luck. According to GDB, I'm receiving a SIGSEV, Segmentation Fault which means that I tried to access an invalid memory address.
Here I'm trying to find the length of the char pointer that is being passed
int getLength(char *start) {
int count = 0;
while(*start) {
count++;
start++;
}
return count;
}
Here is my full C file. I think it might be useful
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
int len1 = getLength(argv[1]);
int len2 = getLength(argv[2]);
if (argc != 3) {
fprintf(stderr, "Invalid number of items input.\n");
return 1;
}
if (len1!=len2) {
fprintf(stderr,"From and to are not the same size.\n");
return 1;
}
return 0;
}
int getLength(char *start) {
int count = 0;
while(*start) {
count++;
start++;
}
return count;
}
int duplicatesFrom(char *from) {
int i;
int j;
int len = getLength(from);
for(i=0;i<len;i++) {
for(j=0;j<len;j++) {
if (from[i]==from[j] && i!=j) {
return 1;
}
}
}
return 0;
}
First, if you don't give at least 3 arguments to your program, it will crash since you call getLength with the second and third argument as parameters at the beginning of main().
I suggest you move the two first lines below the argument count check.
Then, as suggested by BathSheba, you shoud consider making the char * passed to getLength() const since getLength() doesn't modify it. It is a good practice and make the code more self-explanatory.
Also, do not forget the forward declaration of the functions you use in main() if their definition are below main(), unless you put the forward declaration in a header file (neither are present in your code snippet).
On last thing : in getLength(), you should check if the char * passed is valid by doing something like if (start){...}. Because if start == NULL, your program will crash since you will try to access a null pointer.
Following your edit : you can not separate an if() statement and the else if() logically following it. The else if() can be changed to if() here since in the case you enter the first if(), you quit the program (return 1;). And if you don't (if there is 3 arguments passed to the program), you can check safely if argv[1] and argv[2] have the same length.
Your main, slightly modified :
int main(int argc, char *argv[]) {
if (argc != 3) {
fprintf(stderr, "Invalid number of items input.\n");
return 1;
}
int len1 = getLength(argv[1]);
int len2 = getLength(argv[2]);
if (len1 != len2) {
fprintf(stderr, "%s and %s are not the same size.\n", argv[1], argv[2]);
return 1;
}
else {
printf("%s", "Hello\n");
}
return 0;
}
I'm testing a small program which basically compares whether 2 input strings are identical (as strcmp does).
I'd want to do something like (users type 2 desired strings on the same line). In this case it should return "The two strings are different"
./a.out foo bar
should I do this to read the user's input strings?
scanf("%s %s", str1, str2);
or
gets(str1); gets(str2);
Here is what I have so far (it seems to stuck in an infinite loop for some reasons)
int mystrcmp(char str1[], char str2[]) {
int i = 0;
while (str1[i] == str2[i]) {
if (str1[i] == '\0' || str2[i] == '\0') break;
i++;
}
if (str1[i] == '\0' && str2[i] == '\0')
return 0;
else
return -1;
}
int main(int argc, char * * argv) {
int cmp;
char str1[1000], str2[1000];
scanf("%s %s", str1, str2);
//gets(str1); gets(str2);
cmp = mystrcmp(str1, str2);
if (cmp == 0)
printf("The two strings are identical.\n");
else
printf("The two strings are different.\n");
return 0;
}
You should do neither. Instead I suggest you learn about how command line arguments are passed to the main function through the argc and argv arguments.
I suggest you try this program to help your understanding:
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("argc = %d\n", argc);
for (int a = 0; a < argc; ++a)
printf("argv[%d] = \"%s\"\n", a, argv[a]);
}
For your example invocation
./a.out foo bar
the program above will print
argc = 3
argv[0] = "./a.out"
argv[1] = "foo"
argv[2] = "bar"
This solution should work:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
if(argc != 3) {
puts("Wrong number of arguments");
return 0;
}
if(strcmp(argv[1], argv[2]))
puts("The two strings are different.");
else
puts("The two strings are identical.");
}
I am trying to create a shell, and am having trouble trying to fill the *argv[] array with user input. I call my parse function, and store each word into a 2d array. I tried many different ways to store it directly into *argv[], but eventually decided to try using the 2d array. Is there anyway to fill *argv[] with pointers to the strings stored in the 2d array? Or fill *argv[] with pointers to strings without use of the 2d array?
Ive tried many other things but my current attempt is the while loop after calling the parse function.
int main() {
int status, fRedirect, i;
pid_t pid;
char s[STORAGE];
char p[MAXITEM][STORAGE];
char *argv[MAXITEM];
for(;;) {
printf("\2: ");
scanf("%s", s);
parse(s, p);
while(p[i] != '\0') {
args[i] = *p[i];
}
if(p[0] == EOF)
break;
if(p[0] == '\0')
continue;
pid = fork();
if(pid == 0) {
if(execvp(*p, p) == -1) {
printf("Execution failed!\n");
exit(9);
}
}
if(pid != 0) {
wait(-1, &status, 0);
}
else {
fRedirect = open("/dev/null", O_WRONLY);
dup2(fRedirect, STDOUT_FILENO);
}
}
/*killpg(getpid(), SIGTERM);*/
printf("p2 terminated. \n");
exit(0);
}
void parse(char *s, char p[][STORAGE]) {
int i, j = 0;
while(*s != EOF && *s != '&' && *s != '\n' && *s != ';' && *s != '\0') {
for(i=0; i < strlen(s); i++)
p[j][i] = s[i];
i = i+getword(s);
j++;
}
}
I see in your code that you have included char *argv[MAXITEM]; in the function body of main(). This is traditionally not the way *argv[] is used. The main function definition has code within it that handles memory for *argv[]. Parsing the command line arguments into strings, integers, floating point numbers can be done the usual way, using string parsing and conversion functions inside main(). If you are interested, Here is a post explaining char *argv[] with a little more detail,
For a simple example of string arguments (similar to what you are doing) take a look below at how it is used, it may solve a couple of issues for you right away, such as simplifying the way you are obtaining and parsing your input.
First, the answer to your question: Is there anyway to fill *argv[] with pointers to the strings stored in the 2d array? Or fill *argv[] with pointers to strings without use of the 2d array?
No.
However, you can fill it with string constants. char *Argv[] is itself a variable that can contain an array of strings (pointer to an array of strings) when used in main like this:
#include <ansi_c.h>
int main(int argc, char *argv[]) //Note: the`[]` blank brackets allow any string length.
// the `*` allows multiple arguments
{
int i;
for(i=0;i<argc;i++) //argc contains the count of cmd line arguments
{
printf("%s\n", argv[i]); //*argv[] holds multiple string arguments
}
getchar(); //optional - pauses execution so I can see output
return 0;
}
To test:
Build as play.exe, then run it with command line arguments such as:
"argument1" "argument2" "Hello"
The output should be: (essentially, parsing your input into variable strings)
Ok, after working on it some more and adding in more features, Here is what I'm currently working with. To my knowledge, the parse() command now fills *argv[] with the words taken in from the command line.
int main() {
pid_t pid, child_pid;
int argc, inputRedirect;
char *devNull;
devNull = (char *) malloc(10);
strcpy(devNull, "/dev/null");
char *argv[MAXITEM];
char commandLine[STORAGE];
signal(SIGTERM, myhandler);
for (;;) {
printf("p2: ");
scanf("%s", commandLine);
if(commandLine == EOF)
break;
argc = parse(commandLine, argv);
if (argv[0] == '\0')
continue;
if(argv[0] = "cd")
changeDir(argv[1]);
child_pid = fork();
if (child_pid < 0) {
printf("Cannot fork! Terminating...");
exit(1);
} else if (child_pid == 0) {
CHK(inputRedirect = open(devNull, O_RDONLY));
CHK(dup2(inputRedirect, STDIN_FILENO));
CHK(close(inputRedirect));
CHK(execvp(*argv, argv));
}
else {
for(;;) {
CHK(pid = wait(NULL));
if(pid == child_pid)
break;
}
printf("Child's pid is %d\n", child_pid);
}
}
killpg(getpid(), SIGTERM);
printf("p2 Terminated.\n");
exit(0);
}
int parse(char *commandLine, char *argv[]) {
int argc = 0;
char *commandPointer = commandLine;
while (*commandPointer != '\0') {
*argv = commandPointer;
argc++;
getword(commandPointer);
}
*commandPointer = '\0';
*argv = '\0';
return argc;
}