Taking arguments as input from terminal - c

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++.

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;
}

Error: char converts between pointers to integer types with different sign

Question: Write a program anagram that sorts the letters in a word, which is useful when searching for anagrams. anagram takes a single argument, which is a string containing only lower-case letters, sorts the letters alphabetically, and then prints the sorted letters. You may use any sorting algorithm you are familiar with, but you must write the sort function yourself. You may not use any sort function provided by a library.
Usage
$ ./anagram hello
ehllo
$ ./anagram positivity
iiiopsttvy
$ ./anagram abcdef
abcdef
The below code is what I have done so far but I get the error
passing char * to parameter of unsigned char converts between pointers to integer types with different sign
#include <stdio.h>
#include <string.h>
void anagram(unsigned char input[])
{
int count[256] = { 0 };
int i;
for (i = 0; input[i] != '\0'; i++)
{
count[input[i]]++;
}
for (i = 0; i < 256; i++)
{
while (count[i] > 0)
{
printf("%c", i);
count[i]--;
}
}
}
int main(int argc, char* argv[])
{
if(argc > 1)
{
anagram(argv[1]);
}
return 0;
}
The short answer to your question is you are getting the pointer sign mismatch warning because you are attempting to pass argv[1] (type char *) to anagram which you have declared with a parameter of unsigned char * (though you use input[], the practical effect is that input decays to a pointer when used as a parameter)
The simple solution while preserving the unsigned char* type for anagram is to cast argv[1] to (unsigned char *) when passed as a parameter to anagram, e.g.
anagram((unsigned char *)argv[1]);
The more practical question is "Do you really need the unsigned char* type to begin with?" While you can escape and pass non-ASCII values as the argument to your program -- is that something you expect and want to protect against by using the unsigned char* (which is 100% fine to do).
Generally, you would simply declare anagram (char *input) (which is your second alternative to eliminate the signed mismatch on the pointers) and limit your loop to looping over the valid range for ASCII characters (see ASCIItable.com)
Either way is fine so long as you handle the pointer signedness consistently. Putting that altogether and removing the magic numbers from your code, you could do something similar to the following:
#include <stdio.h>
#include <string.h>
#define CHRSET 256 /* if you need a constant, define one */
void anagram (unsigned char *input)
{
int i, count[CHRSET] = { 0 };
for (i = 0; input[i] != '\0'; i++)
count[input[i]]++;
for (i = 0; i < CHRSET; i++)
while (count[i] > 0) {
printf("%c", i);
count[i]--;
}
putchar ('\n'); /* provide a POSIX compliant newline before termination */
}
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf (stderr, "error: insufficient input\n"
"usage: %s <string>\n", argv[0]);
return 1;
}
anagram ((unsigned char *)argv[1]);
return 0;
}
(note: you can also move the output of the final newline to main, but unless you plan on smushing multiple sorted strings together by making repeated calls to anagram, then it is better left after the output of each string)
Look things over and let me know if you have further questions.

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);
}

error: comparison between pointer and integer ('int' and 'string' (aka 'char *'))

I´m starting in C any help will be appreciated.
From a saved string in ´letters´, I want to compare, one by one, if those match the one delivered by the user on argv[]. Moreover, I have a problem on my if clause that I don´t understand.
crypt.c:17:18: error: comparison between pointer and integer ('int' and 'string' (aka 'char *')) [-Werror]
if (g[i] == argv[1])
~~~~ ^ ~~~~~~~
I don´t agree with the compiler this to be a pointer and an integer as I previously defined. g as a string and argv[] as a string. Can someone shed some light in what I am missing, please? I barely know about pointers, can you offer some theory as well? Thanks.
Here's my code:
#include <stdio.h>
#include <cs50.h>
#include <string.h>
int main(int argc, string argv[])
{
if (argc != 2)
{
printf("Wrong Input\n");
}
string g = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
for (int i = 0, n = strlen(g); i < n; i++)
{
if (g[i] == argv[1])
{
printf("True\n");
}
else
printf("False\n");
}
}
I'm going to assume string is typedef char *. (Strings in C are so weird I'd recommend not pretending they're anything but pointers and to not hide that with a string type.)
The trouble is argv is a char **, an array of strings. Whereas g is a char *, or a string. g[0] is the first character of the string, a char. argv[0] is the first string, a char *.
So g[i] == argv[1] is comparing a char with a char *. You probably mean g[i] == argv[1][i].
g is a string, but g[i] is not string anymore. (read: https://www.tutorialcup.com/cplusplus/strings.htm#CharacterArray)
Maybe you can check it as a char.
#include <stdio.h>
#include <cs50.h>
#include <string.h>
// maybe cs50.h have this line inside:
// typedef char* string;
int main(int argc, string argv[])
{
if ((argc != 2) || (strlen(argv[1])!=1))
{
printf("Wrong Input\n");
return 0;
}
// second argument, and first char
char arg = argv[1][0];
string g = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
for (int i = 0, n = strlen(g); i < n; i++)
{
if (g[i] == arg)
{
printf("True\n");
}
else
{
printf("False\n");
}
}
}

C: Accessing the second argv via a pointer

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;
}

Resources