Is it possible to add an argument to main by scanf? - c

I tried to add an argument to main by scanf. But it didn't work. The following is my program. My question is: what's wrong with this program? And is it possible to add an argument to main by scanf() instead of in the command line?
#include <stdio.h>
#include <errno.h>
int main(int argc, char* argv[]){
/*check if there is no argument, that is, argc!=2*/
if(argc != 2){
puts("Please enter an argument: ");
scanf("%s", &argv[1]);
printf("\nYou've entered argument: %s\n", argv[1]);
return 1;
}
printf("\nYou've entered argument: %s\n", argv[1]);
return 0;
}

Yes, code can effectively add arguments.
"The parameters argc and argv and the strings pointed to by the argv array shall be modifiable by the program, and retain their last-stored values between program startup and program termination." C11dr §5.1.2.2.1 2
So this allows code to change argc and argv and change argv[0][0] (if argc > 0) - but wait, there's more...
Can code change the original elements of argv[], like argv[1], etc? That is an open question still hanging in SO here. So let us avoid that.
The way to change the contents of argv[] is to first create an alternate set argv_alt[] array and then assign argv_alt --> argv.
#include <stdio.h>
int main(int argc, char *argv[]) {
// Assume argc == 1
printf("%d '%s'\n", argc, argv[0]);
char a[3][10] = { "abc", "def", "fgh" };
char *argv_alt[] = { a[0], a[1], a[2], NULL };
argc = 3;
argv = argv_alt;
printf("%d '%s' '%s' '%s'\n", argc, argv[0], argv[1], argv[2]);
return 0;
}

Argv is allocated by the system when the user types in her arguments. If there wasn't arguments you cannot use the position 1 on that array. Although, as pointed out on the comments, you shouldn't do the way you are willing to, you could scanf arguments if you declare your own local variable.

The %s specifier in scanf expects that you pass in a pointer which points to space that has already been allocated and is big enough to hold whatever will be read.
Instead you pass in a pointer which points to an area where another pointer is stored. This causes undefined behaviour because the pointer you pass in has the wrong type.
It's not possible to extend the length of the argv array. In fact, writing to argv[n] probably causes undefined behaviour anyway.
Instead you should just read into a variable inside main.

Related

How to add "int argc and char *argv[]" to my main function and impliment into my code?

I am working on creating an uppercase function. I want to implement argc and argv arguments in to my code but I don't know how to do it.
Here is my code;
Main.c:
#include <stdio.h>
#include <stdlib.h>
#include "upperc.h"
int main(int argc, char *argv[])
{
char s[] = "HellO2 world3!";
printf("%s \n", s);
printf("%s \n", uppercase(s));
return 0;
}
upper.c:
/*
Parsing the string, then making the letters to uppercase.
*/
#include <stdio.h>
#include "upperc.h"
char * uppercase(char *s) {
for(char *p = s; *p; ++p) {
if ('a' <= *p && *p <= 'z')
*p = *p & ~' ';
}
return s;
}
upper.h:
#ifndef UPPERC_H_INCLUDED
#define UPPERC_H_INCLUDED
char * uppercase(char *s);
#endif // UPPERC_H_INCLUDED
As this looks like some kind of homework, I don't give a full answer.
argc is the number of arguments including the program name that was executed. That means argc is 1 if no arguments were specified, 2 if one argument was specified etc.
Don't pass argv[1] unconditionally to your uppercase function. This would be undefined behavior if argc is 1 or even 0. (see below for details)
Depending on your requirements, you should check argc and process either only argv[1] if available, which would be the first argument, or process argv[1], argv[2] ... in a loop as necessary.
Additional details (for experts, because my original wording was not exact):
If your program is called in a normal way, the value of argc should be at least 1 and argv[0] will be the program name. The value of argv[argc] is a NULL pointer. Of course you can access the pointer value in this case, but you cannot dereference it, i.e. you cannot access a value where the pointer would be pointing to.
It is possible to call your program in a way that results in an argc value 0. In this case argv[0] will be a NULL pointer, and the array element argv[1] (and all following it) will be undefined.
See https://en.cppreference.com/w/c/language/main_function

String outputting Gibberish [duplicate]

This question already has answers here:
What does int argc, char *argv[] mean?
(12 answers)
Closed 5 years ago.
in my C script my input is printing out gibberish and im not sure why
heres more or less what i have on it
int main (int arg, char argv[])
{
printf(argv);
}
this prints out giberish?
The following should yield the results you are looking for
#include <stdio.h>
int main(int argc, char **argv)
{
// Check if there is at least 2 arguments. First argument is the executable name.
if(argc > 1)
{
// Print out a string, followed by a new-line character.
printf("%s\n", argv[1]);
}
// Exit successfully
return 0;
}
Edit: After looking at your code here and some of the things I recommend to change:
The signature of your main function to int main(int argc, char **argv). Here argc is the argument count, and argv are the argument values. argv is a double-pointer. If we consider char* to be a string (sequence of characters in memory terminated by a null-character, or 0), then argv is a pointer to argc-many strings.
Secondly, to check the first program argument, consider making sure that there is in-fact an argument there. if(argc > 1) will make sure there is at least 1 argument to the program (the 0-index argument to a program is the executable path).
When you want to actually check the value of the first argument, de-reference argv to get a "string" with argv[1] //The first argument. Then you can de-reference this string to get the first character
if ( *(argv[1]) == 'f' )
{
....
}
If you want to check for a full string, rather than just a single character, consider using a function such as strcmp defined in <string.h>.

What arguments does a c application like snmpget take?

I want to call snmpget.c from another c program in the same project. For that reason I have changed the main() into a function say get_func() which takes the same arguments. But i an not sure how to give the arguments namely argv[0]
My arguments look something like this:
char *argstr[]=
{
"v",
"1",
"c",
"public",
"-Ovq",
"192.168.1.1",
"ifInOctets.7",
"ifOutOctets.7",
NULL
};
And then
i = get_func(10, argstr);
1.Should argv[0] be the app name or path?
2.Is using char *argstr[] correct for c?
3.snmpget is not taking these arguments correctly. What could the reason be?
It works correctly with the same args in command.
Your get_func expects the arguments starting at argv[1], so your argstr argument should not start with "v" but with something else (e.g. the programme name or just an empty string if get_func doesn’t use it).
Yes. But be aware that your argstr contains non-modifiable strings, if get_func wants to modify them, you can use compound literals
char *argstr[]=
{
(char []){ "v" },
(char []){ "1" },
/* etc */
NULL
};
See 1. and 2. Additionally, argc is incorrect (must be sizeof argstr/sizeof *argstr - 1, which is 8 in your case, not 10).
Not directly an answer to your question, but consider redesigning this (depends on what exactly you’re currently doing, however). For example, write a function accepting a structure where the different options are stored (already parsed and validated) and change the old main from snmpget.c to a function only scanning and validating arguments, initializing such a structure object, and calling this function. And then, perhaps split your files into snmpget.c, snmpget_main.c, another_c_file.c (with better names, of course) and link both user interface implementations against the object file of snmpget.c.
Yes, if your main uses it. If not, just pass NULL is enough >o<
Sure, it's array of pointers. char *argstr[9] is equal to
typedef char *pchar;
pchar argstr[9];
Well, I assume you don't give appropriate argc and don't pass the app name by argv[0] because the argc is 10, but the number of content of argv is 8. (I've counted excluding NULL, but the NULL is required yet - argv[argc] should be NULL.)
To reduce mistakes, I suggest to use sizeof(argstr) / sizeof(argstr[0]) - 1 instead of calculating argc yourself.
See live example. Code:
#include <stdio.h>
int test(int argc, char *argv[]);
int main()
{
char *argstr[] = {
"test.exe",
"--opt-1",
"--output",
"test.txt",
NULL
};
int argcount = sizeof(argstr) / sizeof(argstr[0]) - 1;
return test(argcount, argstr);
}
int test(int argc, char *argv[])
{
int i;
printf("argc: %d\n", argc);
printf("program name: %s\n", argv[0]);
for (i = 1; argv[i] != NULL; i++)
{
printf("argument %d is: %s\n", i, argv[i]);
}
return 0;
}
Output:
argc: 4
program name: test.exe
argument 1 is: --opt-1
argument 2 is: --output
argument 3 is: test.txt

subsequent printf statement ruining unrelated array

In the following code, the printed result for char array dir is gibberish.
However, if I comment out the indicated printf statement, the printed result is intelligible. What is going on here? Thanks. sing code blocks / gcc.
#include <stdio.h>
#include <string.h>
char* handle_input(int argc,char *argv[]){
char dir[200];
printf("Number of arguments: %d\n",argc);
if(argc<2) {
printf("No argument specified\n");
strcpy(dir,"Default argument");
}
else{
printf("Command line directory was specified\n");
++argv;
strcpy(dir,argv[0]);
}
strcat(dir,"_CAT");
return dir;
}
int main(int argc, char *argv[]){
char* dir;
dir = handle_input(argc,argv);
printf("This one messes it up!\n");
printf("%s\n",dir);
printf("DONE\n");
return 0;
}
In your handle_input function, you're returning a local array, which is a huge no-no; after the function ends, that array no longer exists, and what you return is just nonsense. This invokes undefined behavior later in your program. That printf call happens to overwrite the memory which previously belonged to the array. Without the printf call, that memory just happens to be intact, which is why it comes out intelligibly.
The right way to return an array is like this:
char* handle_input(int argc,char *argv[]){
char* dir = malloc(200 * sizeof(char)); // sizeof unnecessary for char,
// but it's a good habit to have
printf("Number of arguments: %d\n",argc);
if(argc<2) {
printf("No argument specified\n");
strcpy(dir,"Default argument");
}
else{
printf("Command line directory was specified\n");
++argv;
strcpy(dir,argv[0]); // This is unsafe! use strncpy instead
}
strcat(dir,"_CAT");
return dir;
}
Using malloc ensures that the memory allocated will continue to exist after the end of the function, and that you will no longer be causing undefined behavior. Note that arrays are somewhat "special"; you can return primitive values (int, char, etc) and structs without having this sort of behavior occur.
You are returning a local char dir[200] in the function handle_input, after the function exits, it's undefined behavior to access it.
Use dynamic memory allocation instead, like:
char* handle_input(int argc,char *argv[]){
char *dir = malloc(200);
//do the processing
return dir;
}
Remember to free it once it's out of use.
You are returning a local vasriable
Either
Use malloc (as you are in the C world with printf)
Pass in a pointer to be filled up

C application error on run

I've built a C application, and when I build it, it shows no errors, but when I run it, it gives me the error "Segmentation Fault: 11".
If it helps, here is the code I am using:
#include <stdio.h>
int main(char *argv[]) {
printf("The project path is: ./Projects/%c", argv[1]);
return 0;
}
The correct main prototyped syntax is
int main(int argc, char *argv[]) { ... }
Also %c conversion specification in printf prints a character, to print a string use %s.
You have a number of problems:
The signature for main is an argument count followed by an array of C strings.
You should always check the count before using the array.
The array is of strings so you need %s to print them.
This should work:
#include <stdio.h>
int main(int argc, char *argv[]) {
if (argc < 2)
fprintf (stderr, "Wrong number of arguments\n");
else
printf ("The project path is: ./Projects/%s\n", argv[1]);
return 0;
}
Change the signature to int main(int, char*[]);
What arguments are you passing to the process? If you're not passing any argv[1] is out of range
In addition to the other suggestions, you may need to revisit your printf format. %c is used to print a single character, and argv[1] is char *. Either use argv[1][0] or some such, or use the string format specifier, %s.
First, change your main to:
int main(int argc, char *argv[])
Second, you have a mismatch between what you're passing to printf, and what you've told it you're going to pass. argv[1] is a pointer to characters, not a character. You need/want to use the %s conversion to print it out:
printf("The project path is: ./Projects/%s", argv[1]);
In this specific case, it's not really mandatory to check for enough arguments, because even if you don't pass any command line arguments, argv will contain at least argv[0] followed by a null pointer. As such, using argv[1] is safe, but if you haven't passed a command line argument, may print as something like (null).
Nonetheless, you generally want to check the value of argc before using argv. In this case, you can get away with it, but only more or less by accident. Trying to use argv[2] the same way could give undefined behavior.

Resources