String compare function properly - c

I am writing a program that has to use the strcmp function using a pointer in the main. There cannot be any user input. There is no menu, it must execute the arguments as parameters in the main function. my question is am I calling the strcmp function proper?
int main(int n, char **p, char **choice)
{
int i, x, A[100];
if (strcmp(*choice, "mode")==0){

Your code will compile and is grammatically correct, but I'm not certain that the logic is what you want it to be.
Typically main has 2 or 3 arguments, usually written as int argc, char **argv, char ** envp (if there are only 2, it's the first 2). It's ok to rename them as you did, to n, p, and choice, but you need to know what each of them mean.
argc ("n") is the number of strings in the argv array, 0 indexed. There will always be at least 1 argument - the name of the program. Arguments passed on the command line start at argv[1].
argv is all of the arguments, including the program name. The array will go from 0 to argc - 1
envp is an array of strings listing all of the environment settings. It is terminated with a NULL entry as its final one.
If you're tasked with executing the arguments as parameters, you're likely to be interested in looping through the strings in argv. You'll want something like this:
int i = 1;
for (i = 1; i < argc; ++i) {
if (strcmp(argv[i], "mode") == 0) {
Of course, if you want to keep your variable names, just replace them:
int i = 1;
for (i = 1; i < n; ++i) {
if (strcmp(p[i], "mode") == 0) {
So, yes. Your use of strcmp was syntactically acceptable. But it likely doesn't do what you want.
Good luck!
Incidentally, if you ever need to loop through envp, you'd do so as follows:
int i = 0;
while (envp[i] != NULL) {
if (strcmp(envp[i], "mode") == 0) { // or whatever else you needed to do.

Related

finding the size of an string array that saves integers C

I am currently working on a project where I am manipulating command line data, but I can't seem to get it work if I initialize the size of the array before.
char* len2[50]; // will store "1","2","3" from command line args
int size_arr = sizeof(len2) / sizeof(len2[0]);
printf("%d", size_arr);
this will input 50 when I am looking for it to input 3. How would I be able to find the size?
int size_arr = sizeof(len2) / sizeof(len2[0]);
sizeof(len2) asks for the total allocated size of len2 in bytes. This only works because C knows how many you allocated at compile time and turns it into a constant. It doesn't tell you which ones you've filled in. C does not keep track of that; you have to.
Because len2 is an array of pointers, you can mark the end with a null pointer. The term for this is a sentinel value. First, be sure to initialize the array to null.
// This will initialize the entire array to NULL
char* len2[50] = {NULL};
Now you can find how many elements are in the array by looking for the first null, or by hitting the allocated size.
size_t len2_size = sizeof(len2) / sizeof(len2[0]);
int size = 0;
for( ; len2[size] != NULL && size < len2_size; size++ );
printf("size: %d\n", size);
This is, incidentally, basically how C strings work. The end of the string is marked with a 0.
Alternatively, you can store the allocated size and number of elements in a struct and keep track, but that's another question.
Finally, if you're just reading command line arguments, use argc and argv. argc is the size of argv. argv[0] is the name of the program, and the rest are the command line arguments.
int main( const int argc, const char **argv) {
printf("%d arguments in argv\n", argc-1);
}
And argv is also terminated with a NULL pointer so it's easy to iterate through.
// Because argv[0] is the name of the program,
// start at 1 and read until you hit a null pointer.
for( int i = 1; argv[i] != NULL; i++ ) {
printf("argv[%d] = %s\n", i, argv[i]);
}
From the comments:
I guess what I'm trying to find is the number of items. Since there are 3 numbers I'll be getting from the command line, I want to be able to manipulate the array using 3 for a for or while loop for example.
According to the standard you have two versions of main function available (while the implementation defining further ones is legal):
int main();
int main(int, char**);
The second form gets the command line parameters passed to directly while the first form can be used if command line parameters are irrelevant.
Typically (but not necessarily) these two arguments get named argc and argv with argc containing the total number of command line arguments and argv a null-terminated array to the actual arguments. First one of is always the name that has been used to call the programme (which can differ in some cases from the actual executable name, e.g. if symbolic links are involved) which you might want to skip.
So a programme simply iterating over all arguments and printing them back to console might look like this:
int main(int argc, char* argv[])
{
for(++argv; *argv; ++argv)
{
printf("%s\n", *argv);
}
return 0;
}
with first ++argv skipping the programme name, *argv profiting from and testing for the null-terminator of the array and second ++argv being the normal loop post operation.
If you want to see the programme name as well you might just skip very first pointer increment:
for(;*argv;++argv)
Alternative variants might use an integer to count up to argc – just a matter of personal taste...

Why we use argc as argument in getopt() function?

I have recently started learning C language so I don't much about the functions of C.
Recently I saw a program written in C on Internet article. It was like this:-
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int i = 0;
int j = 0;
char ch;
ch = getopt(argc, argv, "n:");
if(ch == 'n')
{
j = atoi(optarg);
}
while(j--)
{
printf("%i\n",j);
}
return 0;
}
Can anyone tell what is the actual purpose of argc in getopt() function? Does it uses argc as for upto where it should read options?
In my observation argc is there to write simple code and the argv NULL to write defensive code.
argv and argc has been in main's signature since the very beginning of C, so has the NULL at the end of the argv list. I've looked at many C programs since then and almost none of them depend on that NULL. Rather they depend on argc to control the array depth as it is simpler and more reliable. However, the defensive programmer will also look for that NULL as well as using argc and getopt() should use argc to complain if it's called too many times.
Also, I've seen code that plays games to reuse getopt() to parse secondary "command lines" for commands given to the application. Not all of those put a NULL on the end of the list (mine did, though).
The C standard does guarantee that argv[argc] is a NULL pointer:
C Standard, §5.1.2.2.1.2:
If they are declared, the parameters to the main function shall obey the
following constraints:
...
— argv[argc] shall be a null pointer.
Technically, all you (and the function getopt) really need is argv - something like this will process all arguments:
int i;
for(i = 0; argv[i]; i++)
{
puts(argv[i]);
}
However, there is nothing stopping you (or the author of getopt) from using argc as a loop guard instead. This is equally valid:
int i;
for(i = 0; i < argc; i++)
{
puts(argv[i]);
}
So, if the function says it requires argc to be passed, then pass argc to it, because it probably uses it to form that type of loop.

warning: assignment makes integer from pointer without a cast, sorting arguments

I know this was asked a few times, but I still do not fully understand the issue.
I have an assigment where I need to save and sort the arguments.
int main(int argc, char* argv[])
{
int c;
char* s = malloc(argc * sizeof(char));
extern char *optarg;
extern int optind;
extern int optopt;
while ( (c = getopt(argc, argv, ":adh")) != -1) {
s[argc] = argv;
switch (c) {
case 'a': printf("a\n");
break;
case 'd': printf("d\n");
break;
case 'h': printf("h\n");
break;
}
}
return 0;
}
I know that it has something to do with me saving a pointer to an integer or not doing it.
char* argv[] is what? An array of pointers?
And s is only an array of chars?
char* argv[] is what? An array of pointers?
When such a declaration appears in a function prototype, as in your code, it is equivalent to char **argv. That's a pointer to a pointer to char. In this particular case, the pointed-to pointer is the first element of an array of pointers.
And s is only an array of
chars?
As you have declared an initialized it, s is a pointer to char, and in particular, it points to the first char in a dynamically allocated block. You can use the block via s as if it were an array of char, but it is not technically an array, and s definitely is not an array. Although related, pointers and arrays are very different things.
The compiler should have told you at least on which line the error occurs, but you did not pass that information on to us. Nevertheless, I think I can guess. This line ...
s[argc] = argv;
... is nonsense. Since s is a pointer to char, s[argc] designates one char (and in C, char is among the integer data types). On the other hand, argv is a pointer (to pointer to char). Although C permits pointers to be converted to integers, it is rarely useful to do so, and anyway, a conforming program must use a cast to perform such a conversion. Since you don't actually use s for anything, your best bet is probably to just remove that line.
For what it's worth, if you wanted to set s to point to one of the command line arguments, say the second, the syntax would be
s = argv[2];
(The zeroth element of argv is conventionally the name of the program; the arguments start at index 1.) But if you intend to do that then you don't need to malloc() any memory for s; whatever you do allocate for it is leaked when you assign a new value to it.
char *argv[] is a pointer to an array of strings. AKA char **argv
int argc is an integer count of the number of strings on the command line, including exe name.
Note also that the length of each string in argv[] has nothing to do with the value of argc. The strings can be as short as two characters, such as a\0 or as long as (or longer than) 1000 characters.
So the statement char* s = malloc(argc * sizeof(char)); will not do what you are thinking it will do.
First it is the form of an expression that will create some space for only one string, not argc of them.
Second, if your command line included 3 item, ( argc == 3 ) and one of the arguments was a string of length 9, say arguments, then your malloc statement would create space for 1 string, with only 3 characters. Not big enough to contain the string `arguments\0', not to mention the other two.
Use something like the following to determine the length of the longest of the argc strings:
int len = 0, lenKeep = 0;
for(i=0;i<argc;i++)
{
len = strlen(argv[i] > len)
if(len > lenKeep) lenKeep = len;
}
Now, lenKeep + 1 has been established as the length needed to contain the longest string (+ 1 for the NULL character, which strlen(...) does not include in its count.). This can be used, along with knowing the number of strings, argc, to allocate memory for each of them.
For example:
int main(int argc, char* argv[])
{
...
char **string = Create2DStr(argc, lenKeep + 1);//will create space
//sufficient to contain
//strings of your command line
...
}
Where Create2DStr(...) could be defined as:
char ** Create2DStr(ssize_t numStrings, ssize_t maxStrLen)
{
int i;
char **a = {0};
a = calloc(numStrings, sizeof(char *));
for(i=0;i<numStrings; i++)
{
a[i] = calloc(maxStrLen + 1, 1);
}
return a;
}

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

Basic C Pointer

I'm a beginner in C and have been trying to figure out what has gone wrong with my code code for the past hour or two. I have been following through K&Rs book and I keep looking through it but still do not understand my logic mistake.
while (*argv>0){
while (**argv>0){
printf("%c\n",**argv);
**argv++;
}
argv++;
}
Task:Print out all the arguments being fed to my program using argv.
To my understanding, argv is a pointer to an array that contains further pointers to arrays of character pointers. So, I said that while *argv>0 or while the first array still has elements, we should follow the pointers from the first array to the next array. Then we should print out all the elements in the next array.
Too many * in this line:
**argv++;
It should be like this:
*argv++;
Plus additional braces, because the ++ operation has higher priority:
(*argv)++;
And it will work.
I suggest you don't confuse yourself by using pointer dereferencing the way you do when the subscript notation ([]) allows you to do the same.
#include <stdio.h>
int main(int argc, char** argv)
{
int i;
for(i = 0; argv[i]; i++)
printf("%s\n", argv[i]);
return 0;
}
This will also print argv[0], which is the name/path of the program.
Now what does my code do? for(i = 0; argv[i]; i++) counts up i from 0 to the element when argv[i] resolves to false (i.e. 0 aka NULL), that is the last element of the argv array. And then for every element in the array it uses the %s format specifier of printf to print it. You could also pass the argv[i] as the first and only parameter to printf, but that is usually frowned upon as it opens the door for certain string formatting attacks.
argv is of type char *argv[] i.e. a pointer to an array of strings (char*'s). argv++ moves to the next string in the array.
Usually this function would be written as follows:
int main(int argc, char *argv[]){
int i;
for (i = 0; i < argc; i++){ //loop from 0 to argc (argument count)
printf("%s ", argv[i]);
}
return 0;
}
this will work::
while(argc--)//can't use *argv here, because *argv would be the address of the
// element which argv is pointing to, just by knowing the address u can't say whether it still has elements or not
{
while( **argv )
{
printf("%c", **argv);
(*argv)++; //by using **argv++, you are actually moving argv to next array, not to the next character of current array
}
argv++;
printf("\n");//move your \n to here, else you will end up printing every character in a new line
}

Resources