C: Accessing the second argv via a pointer - c

As I'm quite new to C, there's something I don't yet get about pointers. I'd like to check wether a command line argument is integer or not, but in a separate function, so that I pass in the pointer of the argv array.
int main(int argc, char* argv[]){
if(check(argv)){
// Do stuff to argv[1]
}
}
int check(char* p){
// Test wether p+1 is int
return 1;
}
I have tried several things mostly resulting in weird printf's (when printing the dereferenced pointer to test the value).
int i = atoi(argv[1]);
Works just fine, of course. But as the pointer is the only thing passed to the function, I'm paralysed.

Argv is a two dimensional array, which is to say that argv is an array of arrays. Specifically, argv is an array of char arrays. Now, the data that argv is storing is the arguments passed from the command line to the program, with argv[0] being the actual name of the program and the rest being the arguments.
Now, to answer your question, you need to not pass argv in its entirety to the function "check". What you need to do is pass one of argvs elements. This is because the parameter to "check" is a char array, and argv is an array of char arrays. So try passing argv[1] to check the first argument.
Edit: Try this to check all arguments except the name of the program
#include <stdio.h>
#include <ctype.h>
int main(int argc, char* argv[]) {
for (int i = 1; i < argc; ++i) {
if( check(argv[i]) ){
// Do stuff to argv[i]
}
}
int check(char* p){
int i = 0;
char c = p[i];
while (c != '\0') {
if (!isdigit(c))
return 0;
c = p[++i];
}
return 1;
}

int check(char* p){
The above function expects a pointer to a char while you are passing argv which is array of char *
Try
int check(char* p[]){
Also before using argv[1] check if argv[1] exists ie check argc
int main(int argc, char* argv[]){
if(argc>1 && check(argv)){
// Do stuff to argv[1]
}}

Before indexing an array of pointer, we have to be sure it's valid. We have to use argc to this purpose.
strtol is a function which parse a string and detect error if it's not of the base asked.
Ty this:
int main(int argc, char* argv[]){
if(check(argc, argv)){
// Do stuff to argv[1]
}
}
int check( int argc, char * argv[] ){
if( argc > 1 ) {
char * err = NULL;
strtol( argv[1], &err, 10 );
return argv[1][0] != '\0' && *err != '\0';
}
return 0;
}

Related

How do I get the number of elements a char array points to?

I was researching but could not find a way. I am passing 2 char array pointers to a function and fill those 2 arrays with values. Is there a way to get the size of the filled arrays?
I tried size_t size = sizeof(*arguments)/sizeof(arguments[0]) already but that gave me 1 as a result, I know why its giving me 1 as result by researching but I just couldn't find a way to get the proper array length(the value how much elements are in the array). If that is not possible how can I work around this ? I need to know this because, I wanna give the last value of any array a NULL for my exec functions.
My programs works as follows:
An user inputs 2 program names which are executed.
But the 2 programs are separated by a ";". So I have 2 arrays which can vary in size , which depends on the input in the terminal.
void getArguments(char * [],char * [], int ,char * []);
int main(int argc, char * argv[]){
pid_t pid,pid2;
char * arguments2[argc/2+1];
char * arguments[argc/2+1];
getArguments(arguments, arguments2,argc,argv);
if((pid=fork())==-1){
printf("Error");
}
else if(pid == 0){
execvp(arguments[0],arguments);
}
else{
if((pid2 = fork())== -1){
printf("Error" );
}
else if(pid2 == 0 ){
execvp(arguments2[0],arguments2);
}
else{
int status;
wait(&status);
exit(0);
}
}
return 0;
}
void getArguments(char * arguments[], char * arguments2[],int argc, char * argv[]){
int i=0;
while(strcmp(argv[i+1],";")!=0){
arguments[i] = argv[i+1];
i++;
}
arguments[argc/2-1]= NULL;
int j = i+2;
int k = 0;
for( ;j<=argc; j++){
arguments2[k] = argv[j];
k++;
}
arguments2[argc/2-1]=NULL;
}
No, you can't get the size of an array if you only have a pointer. You must pass the size as a separate argument to your function.
EDIT: I now understand you need to return from your function the number elements used in the array. You can either add two integer pointer variables that receive the size, or you could set the first unused element to NULL so the caller knows when it is at the end of the filled portion.
For example:
char * arguments2[argc]; // as you don't know the result, do not divide by 2: it may be too small!
char * arguments[argc];
int size1=0, size2=0;
getArguments(arguments, &size1, arguments2, &size2, argc, argv);
And:
void getArguments(char *arguments[], int *size1, char *arguments2[], int *size2, int argc, char *argv[])
{
// ...
*size1= i;
//...
*size2= j;
}

In C, how to set an unsigned char array from argv

In the code below, I would like to have the value of myvar be provided by a program argument.
#include <stdio.h>
int main(int argc, const char **argv)
{
const unsigned char myvar[] = "myvalue";
return 0;
}
How would I get myvar to contain the value of the string from argv[1]?
If you are only reading, then you can simply copy the address of argv[1] like this:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char **argv) {
const unsigned char *myvar = NULL;
// Be sure to check argc first
if (argc < 2) {
fprintf(stderr, "Not enough arguments.\n");
return EXIT_FAILURE;
}
myvar = (const unsigned char *)argv[1];
printf("myvar = %s\n", myvar);
}
If you want to change myvar then you should copy the string with strncpy or alike.
An array cannot be initialized by a pointer or by another array. You can only initialize it with an initializer list or (in the char of a char array) a string constant.
What you can do it copy the contents of another string with strcpy. And since you'll be using this array as a parameter to an encryption function, it will probably need to be a fixed size.
char myvar[8] = { 0 }; // initialize all values to 0
strncpy(myvar, argv[1], 8); // copy the first 8 bytes

Test case failing at specific line. Manually works fine - C (needle in haystack)

I have a C program that takes arguments from the command line. Prints the arguments in reverse order. And finds the needle/substring in the haystack. I have the following code:
Dumb.c
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "Dumb.h"
int main(int argc, char **argv)
{
int i, j, flag = 0;
for (i = 1; i < argc; i++)
{
char needle[] = "dumb";
int length = strlen(argv[i]);
for (j = length - 1; j >= 0; j--)
{
printf("%c", argv[i][j]);
argv[i][j] = tolower(argv[i][j]);
}
char *pch = strstr(argv[i], echo);
if(pch)
{
flag = 1;
}
}
if (flag == 1)
{
printf("Dumb was found!\n");
}
return 0;
}
It works perfectly when I try to run it manually from command line using: ./a.out Dumb.
But when I try to use a special test case for it, it just crashes at this line: argv[i][j] = tolower(argv[i][j]);
Here is the code for the testing:
TestLauncher.c
int unit_test(int argc, char **argv);
int main(int argc, char **argv)
{
unit_test(argc, argv);
return 0;
}
Test.c
int __hide_main__(int argc, char **argv);
int unit_test(void)
{
int retval;
char **array;
array = malloc(sizeof(char *) * 2);
array[0] = "./a.out";
array[1] = "Dumb";
retval = __hide_main__(2, array);
free(array);
return retval;
}
When you use the string literal "Dumb", it is read-only, unlike the command-line arguments. To see this, try running the following and you should get the same error:
char *arr = "Dumb";
arr[0] = 'd';
To fix this, you should copy the value of argv into a new array rather than modifying it in-place.
But when I try to use a special test case for it, it just crashes at this line: argv[i][j] = tolower(argv[i][j]);
Your program is having undefined behavior as you are trying to modify the string literal. When a program is having undefined behavior, anything can happen like it may work as expected, it may crash etc.
Change this:
array[1] = "Dumb";
to this:
array[1] = strdup("Dumb");
It works perfectly when I try to run it manually from command line using: ./a.out Dumb.
From C Standards (5.1.2.2.1p2):
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.
So, it is perfectly fine to modify the argument vector which contains the list of the arguments passed (including program name) when running from command line.
Hence the program is working fine when running from command line.
Also, in your program unit_test function declared as:
int unit_test(int argc, char **argv);
but in the definition the signature is not matching:
int unit_test(void)
The compiler must be giving conflicting types error for this or I believe its a typo while you have edited your program before posting.
Follow the good programming practice, always check the malloc return:
array = malloc(sizeof(char *) * 2);
if (NULL == array) {
fprintf (stderr, "Failed to allocate memory");
exit(EXIT_FAILURE);
}

Taking arguments as input from terminal

this is part of a function that takes input from terminal and sorts them depending on what the inputs are (sorting type, a version/variation of the sorting method to use, and the size of the array). This is what I have so far:
int main(int argc, char * argv[]) { //will have 3 arguments not including function name: sortingtype, version and arr size
int * arr = make_arr(argv[2], argv[3]); //[2]
if (strcmp(argv[1], "sortingtype1") == 0) {
SortingType1(arr, argv[3]); //[2][3]
}
else if (strcmp(argv[1], "sortingtype2") == 0) {
SortingType2(arr, argv[3]); //[2][3]
}
else {
return 0;
}
}
void test(){ //[1]
main("sortingtype1", "a", 10); //sortingtype, version and arr size
}
[1] I have a function test() to simulate input from terminal but I don't know if it works that way. I get an error saying that there are too many arguments to main.
[2] Whether or not I remove that testing function, I still get warnings about "passing argument (the arguments with argv[X]) makes integer from pointer without a cast".
[3] These also need to be type int and not type char*, how do I change them?
Any suggestions on how to go about this? I have seen solutions using sscanf, but would prefer a more basic solution around my skill level first for understanding.
Edit: segmentation faults from
int * SortingType2(int * arr, int len) {
for (int i=1; i < len; i++) {
int x = arr[i];
int j = i;
while ((j > 0) && (x < arr[j-1])) {
arr[j] = arr[j-1];
j--;
}
arr[j] = x;
}
return arr;
}
int main(int argc, char * argv[]) {
int size;
if (argc > 3) size = atoi(argv[3]);
int * arr = make_arr(argv[2][0], size);
if (strcmp(argv[1], "sortingtype1") == 0) {
SortingType1(arr, size);
}
else if (strcmp(argv[1], "sortingtype2") == 0) {
SortingType2(arr, size);
}
else {
return 0;
}
}
argv[] is an array of strings, so you need to convert them if you want integers. The simplest way to do this is with atoi() or sscanf(). atoi() is in stdlib.h, and sscanf() is in stdio.h. With atoi(), you just give it a string, and it returns an int. With sscanf(), you provide a string, conversion specifiers, and addresses of variables, just as in the scanf() function, the difference being that here you are scanning a string instead of stdin. Here is an example:
#include <stdio.h> // needed for atoi()
#include <stdlib.h> // needed for sscanf()
int main(int argc, char *argv[])
{
int i = 0;
int j = 0;
/* if argv[1] exists, convert to int */
if (argc > 1)
i = atoi(argv[1]);
/* if argv[2] exists, convert to int */
if (argc > 2)
sscanf(argv[2], "%d", &j);
printf("%d -- %d\n", i, j);
return 0;
}
If you compile this code and execute it you get, for example:
david scratch λ> ./a.out 123 456
123 -- 456
Working with your code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char * argv[])
{
int size;
if (argc < 4) {
printf("Usage: %s sortingType state size\n", argv[0]);
exit(EXIT_FAILURE);
}
size = atoi(argv[3]);
int * arr = make_arr(argv[2], size);
if (strcmp(argv[1], "sortingtype1") == 0) {
SortingType1(arr, size);
}
else if (strcmp(argv[1], "sortingtype2") == 0) {
SortingType2(arr, size);
}
return 0;
}
If you want to call main() from a function, then you have to pass an argument count and a pointer to an array of strings that is null terminated (see What should main() return in C and C++? for the details).
Thus, you might write:
void test(void)
{
char *argv[] = { "sortingtype", "a", "10", 0 };
main(3, argv);
}
It is not common to do this. There is no evidence in your code of the test() function being called.
Note that the arguments are not modifiable strings in the code shown above; normally, the arguments are modifiable. If that's going to matter, you have to work a bit harder:
void test(void)
{
char arg0[] = "sortingtype";
char arg1[] = "a";
char arg2[] = "10";
char *argv[] = { arg0, arg1, arg2, 0 };
main(3, argv);
}
Note too that all the arguments in argv should be strings. Your original code seemed to try to pass 10 rather than "10" but that is not allowed in the argument vector (though 10 could be valid as the argument count, of course).
Please note that calling main() recursively is an eccentric thing to do at best. It is seldom actually necessary, or desirable. It is, however, legal in C — but it is not legal in C++.

Copying a char array to another const char array during declaration

What I am trying to do is take a string pointed to by argv[1] and copy it into another array, but I want this new array to be const.
Is there a way to declare the array as const and initialize it with the contents of argv[1] on the same line?
The problem I'm having is that I can't declare it as const and then on the next line copy the string over using strcpy or some such function. That's invalid.
What's the best course of action?
You could do something like this:
#include <stdio.h>
int main(int argc, char *argv[])
{
const char *argument = argv[1];
printf("%s\n", argument);
return 0;
}
leveraging the fact that argument[0] is substantially the same of *argument.
But beware!
int main(int argc, char *argv[])
{
const char *argument = argv[1];
printf("%s\n", argument);
argument[2] = 'z'; //ERROR
printf("%s\n", argument);
return 0;
}
this above causes an error as expected. But...
int main(int argc, char *argv[])
{
const char *argument = argv[1];
printf("%s\n", argument);
argv[1][2] = 'z'; //same memory location but no errors
printf("%s\n", argv[1]);
printf("%s\n", argument);
return 0;
}
causes no error .... in fact in the last printf you can see that your string has been edited.
Considering you don't want to modify it (it being a const and all), you don't even need to copy it somewhere:
(Basic code lacking sanity checks such as correct argument count and argument lenght)
const char *myPointer = NULL;
myPointer = argv[1];
Now myPointer is pointing to argv[1], your first argument that the program was launched with.
So if you launch your program like myfolder/myexe.exe myArg your myPointer will point to a char array with these contents {'m','y','A','r','g','\0'}

Resources