How to read command-line arguments as integers instead of strings? - c

Sorry for my question, I know there are a lot similars but I didn't found any that is simple enaugh to help me.
I've started coding in C and try to solve a simple exercise: Read an integers array from command line, sum the elements using the function array_sum and print result. (input example array of 3 elements: 3 0 1 2)
int array_sum(int *array, size_t size);
int main(int argc, char **argv){
int sum=array_sum(argv, argc);
printf("array_sum: %i\n", sum);
return 0;
}
my problem is that argv is a char array and the function want an integer array.
Should I convert elements one by one in a new int array? There are better ways?

argv is an array of pointers to C strings. You need to convert the strings into integers first. You can do something like this:
int array_sum(int *array, size_t size);
int main(int argc, char **argv){
int *num_arr = malloc((argc - 1) * sizeof *num_arr);
for (int i = 0; i < argc - 1; ++i)
num_arr[i] = atoi(argv[i+1]);
int sum = array_sum(num_arr, argc - 1);
printf("array_sum: %i\n", sum);
free(num_arr);
return 0;
}
The only way to make the code in main shorter is by moving the conversion loop into a separate function that returns the malloced pointer.

In your code, char *argv[] is an array of char* pointers supplied from the command line. In order to convert the numbers supplied, you can use the following:
atoi(), which converts string arguement to an integer type.
Or strtol(), which converts the initial part of a string to a long int, given a base.
Other special functions from C99, alot of which are described in this post.
Since atoi() has no error checking, it is best to use strtol(), which allows extensive error checking.
You should store these converted numbers in a dynamically allocated int* pointer, which will need to be allocated on the heap using malloc(), which was suggested by #StoryTeller in his answer. You could also just declare an array on the stack, such as int arr[n]. The problem arises when you want to return this array in a function, which is not possible. Using a pointer in this case would allow more flexibility for abstraction.
malloc()allocates block of memory on the heap, and returns a void* pointer to it.
Note: malloc() should always be checked, as it can return NULL. You need to also free() this pointer at the end.
Here is some example code:
#include <stdio.h>
#include <stdlib.h>
#define BASE 10
/* Guessed that your function would look like this */
int array_sum(int *array, size_t size) {
int sum = 0;
for (size_t i = 0; i < size; i++) {
sum += array[i];
}
return sum;
}
int main(int argc, char *argv[]) {
int *arr = NULL;
char *endptr = NULL;
int check, sum;
size_t ndigits = (size_t)argc-1;
/* allocate pointer */
arr = malloc(ndigits * sizeof *arr);
if (arr == NULL) {
fprintf(stderr, "Cannot %zu spaces for integers\n", ndigits);
exit(EXIT_FAILURE);
}
for (size_t i = 0; i < ndigits; i++) {
/* sufficient checking for strtol(), more can possibly be added here */
check = strtol(argv[i+1], &endptr, BASE);
if (endptr != argv[i+1] && *endptr == '\0') {
arr[i] = check;
}
}
sum = array_sum(arr, ndigits);
printf("array_sum: %d\n", sum);
/* pointer is free'd */
free(arr);
arr = NULL;
return 0;
}
Example input:
$ gcc -Wall -Wextra -std=c99 -o sumcommands sumcommmands.c
$ ./sumcommands 3 2 1
Output:
array_sum: 6
Note: You can use more error checking for strtol() on the Man page.

Why do you need to pass an int array as argument to the function ? No need to create an extra int array when you can simply do this :
int array_sum(char **argv, int argc){
int sum = 0;
for(int i = 0;i < argc - 1;i++){
sum += atoi(argv[i])
}
return sum;
}

You can use atoi() function to convert char ** array to **int . what i see here is each integer you type is converting into string rather than char.

Related

char** argv passed as array of string

What I know about this code is that in the void cylinder function char** argv is a array of string and numbers are stored in this. I dont know how to convert this array into the int values and then use it.
void cylinder(int argv_size, char** argv){
//comlete this code
}
int main(){
int n;
scanf("%i",&n);
char* *a = malloc(sizeof(char*) * n);
for(int i = 0; i<n;i++){
a[i] = (char *)malloc(1020 * sizeof(char));
scanf("%s",a[i]);
}
cylinder(n,a);
return 0;
}
You might want to check if some arguments/ no arguements have been passed:
if(argc==1)
printf("\nNo Command Line Argument Passed Other Than Program Name");
if(argc>=2)
{
printf("\nNumber Of Arguments Passed: %d",argc);
for(int counter=0 ; counter<argc ; counter++)
printf("\nargv[%d]: %s",counter,argv[counter]);
}
Then, to convert the passed integer(passed as a string) value use atoi, like: atoi(argv[1]) if only one integer value has been passed.
Note: use #include<stdlib.h> for atoi()
I see some disadvantage in your code:
scanf("%s",a[i]);
Should change to (see disadvantages of scanf ):
scanf("%1019s",a[i]);
//OR
fgets(a[i], 1020, stdin);
You should check the result of malloc function, and do not cast malloc as i see you allocated for a[i]:
char* *a = malloc(sizeof(char*) * n);
if(!a) {
//handle the error
return -1; // for example
}
and
a[i] = malloc(1020 * sizeof(char));
if(!a[i]) {
//handle the error
}
You have to free the memory of each a[i] and a after cylinder function to avoid memory-leaks.
For cylinder function:
void cylinder(int argv_size, char** argv){
for(int i = 0; i < argv_size; i++) {
// convert argv[i] to int by using sscanf, atoi, strol, etc.
// for example i use atoi function:
printf("value of (int)argv[i] = %d", atoi(argv[i]);
}
}
You can also find other function for converting string to int in this link How to convert a string to integer in C?

Understanding why it does not find duplicates in array

I wrote the following function in C:
int last(long arr[], int length) {
for (int i = 0; i < length-1; i++)
if (*(arr+i) == *(arr + length - 1))
return 1;
return 0;
}
it checks if the last value of the array was used more than once. In the main:
int *arr = malloc(length*sizeof(int));
for (int i = 0; i < length; i++)
scanf("%d", ++arr);
printf(last((long *) arr, length);
For some reason for the array [1,2,2,3] it returns that the last element was used multiple times and I'm not sure why. I think that is because of scanf("%d", ++arr); but I don't know how to fix it.
My goal is that it will return 1 for [1,3,2,3] and 0 for [1,2,2,3]. What could be the problem?
You should use scanf("%d", &arr[i]);. Using ++arr causes the array to be incremented before you pass it to last, and also reads into data beyond arr, which is undefined behavior.
Another one of the issues in this is the cast to long *.
You should use %ld in scanf and long *arr = malloc(length*sizeof(*arr));.
Also make sure to check for NULL. You never know when malloc is going to fail or someone's going to pass bad data.
Full example:
#include <stdio.h>
#include <stdlib.h>
int last(long arr[], int length) {
if(!arr) return -1;
for (int i = 0; i < length-1; i++)
{
if (arr[i] == arr[length-1])
return 1;
}
return 0;
}
int main(void)
{
long *arr = malloc(4*sizeof(*arr));
if(!arr) return 1;
for (int i = 0; i < 4; i++)
scanf("%ld", &arr[i]);
printf("%d\n", last(arr, 4));
}
Several problems in your code:
Look at this statement:
scanf("%d", ++arr);
^^^^^
In the last iteration of loop, the pointer arr will be pointing to one element past end of array arr (due to pre-increment) and it is is passed to scanf(). The scanf() will access the memory location pointed by the pointer which is an invalid memory because your program does not own it. This is undefined behavior. Note that a pointer may point to one element past the end of array, this is as per standard but dereferencing such pointer will lead to undefined behavior.
Once the main() function for loop finishes the arr pointer pointing to location past the end of memory allocated to arr and just after this you are passing arr to last() function. So, you are passing an invalid memory reference to last() function and then accessing that memory in last() function - one more undefined behavior in your program.
Probably you should take another pointer and point it to arr, so that arr keep pointing to allcoated memory reference returned by malloc().
Note that if you want to read the input the way you are doing then use the post-increment operator in scanf(), like this:
int *arr = malloc(length*sizeof(int));
if (arr == NULL)
exit(EXIT_FAILURE);
int *ptr = arr;
for (int i = 0; i < length; i++)
scanf("%d", ptr++);
but the more appropriate and readable way is - scanf("%d", &arr[i]).
Another big problem in your code is accessing the int values as long type.
The last() function parameter arr type is long and you are passing it int pointer typecasted to long *.
Note that the size of long and int may be different based on the platform. You cannot assume them to be of same size on all platforms.
Assume the case where int size is 4 bytes and long size is 8 bytes.
In this case, when accessing an int pointer using long type pointer then every object will be considered as 8 byte long and when you do arr+1 in last(), the pointer will be advance by 8 bytes and you will never get correct result.
Compiler must be throwing warning message on this statement:
printf(last((long *) arr, length);
because the printf() expects first argument as const char * and you are passing it int (return type of last()). You should give the first argument to printf() a string which contains appropriate format specifier('s).
Putting these altogether:
#include <stdio.h>
#include <stdlib.h>
int last(int arr[], int length) {
if (arr == NULL) {
return 1;
}
for (int i = 0; i < length - 1; i++) {
if (arr[i] == arr[length - 1]) {
return 1;
}
}
return 0;
}
int main(void) {
int length = 4;
int *arr = malloc (length * sizeof (*arr));
if (arr == NULL) {
exit(EXIT_FAILURE);
}
printf ("Enter %d numbers:\n", length);
for (int i = 0; i < length; i++) {
scanf ("%d", &arr[i]);
}
printf ("Duplicate found: %s\n", last (arr, length) == 1 ? "Yes" : "No");
return 0;
}

using a function to initialise an array variable in C

I am a complete beginner.
I have a function which converts an int to an array.
#include <math.h>
#include <stdio.h>
int *convertIntArray(int number) {
int n = log10(number) + 1;
int i;
int *numberArray = calloc(n, sizeof(int));
for (i = 0; i < n; ++i, number /= 10) {
numberArray[i] = number % 10;
}
return numberArray;
}
I'd like to initialise an array named sample in my main function, by passing an integer to the convertIntArray function. My pseudocode looks like:
int main(int argc, char *argv[]) {
int sample = convertIntArray(150);
// rest of main function
But obviously this doesn't work. What is the correct way to do this?
The array is allocated by the converIntArray function and a pointer to its first element is returned. You can store this pointer to array in main if you define array with the appropriate type:
int main(int argc, char *argv[]) {
int *sample = convertIntArray(150);
// rest of main function
Note however that you cannot tell the size of the array pointed to by array from the pointer and the values. You should return either always allocate the maximum size, which is 10 int or return the size some other way, for example as the first element of the array, which you would then allocate with an extra element.
The first thing to note in your code is that you don't include a prototype for function log10() which I guess should be in <math.h>. Or you have done it, but didn't show it in your snippet of code. This is bad posting in StackOverflow, because that leaves us in the dilema of deciding if you made a mistake (by not including it, which will give you undefined behaviour, so, please edit your question, including a minimal, complete and verifiable example.
In case I had to write your function, I should not use log10() because it is a floating point function and you can select the wrong number of digits to allocate in case there's some rounding error in the calculation. Anyway, I'd try to use as less support functions as possible, by changing your interface to this one:
unsigned *number2digits(
unsigned *array_to_work_in, /* the array is provided to the function */
size_t array_size, /* the size of the array, in number of elements */
unsigned source_number, /* the number to be converted */
unsigned base); /* the base to use for conversion */
This approach doesn't force you to include the math library only for the log10() function, and also doesn't make use of the dynamic allocator routines malloc() and calloc(), and the compiler optimises it better if the function doesn't call more external/library functions. In case (see below) you want to use the function on an already allocated array, you don't have to rewrite it. Also, the numbering base is a good thing to pass as parameter, so you are not stuck to base 10 only numbers.
Another error is that you are returning an int * (pointer to int) and you assign the value to a variable of type int (this is a mistake that should have given you a compiler error).
A valid (and complete, and verifiable) example code should be:
#include <stdio.h>
#include <stdlib.h>
unsigned *number2digits(
unsigned *array_to_work_in, /* the array is provided to the function */
size_t array_size, /* the size of the array, in number of elements */
unsigned source_number, /* the number to be converted */
unsigned base) /* the base to use for conversion */
{
size_t i;
for (i = 0; i < array_size; i++) {
array_to_work_in[i] = source_number % base;
source_number /= base;
}
/* if, at this point, source_number != 0, you made an error
* on estimating array size, as the number doesn't fit in
* array_size digits. In case of error, we return NULL to
* indicate the error. */
return source_number == 0 ? array_to_work_in : NULL;
}
#define NUMBER 150000
#define N 10
#define BASE 38
int main()
{
unsigned my_array[N]; /* 10 digits for a base 38 is enough for a 32 bit integer */
unsigned *r = number2digits(my_array, N, NUMBER, BASE);
if (!r) {
fprintf(stderr, "Error, number %u does not fit in %u base %u digits\n",
NUMBER, N, BASE);
exit(EXIT_FAILURE);
}
printf("%u =/base %u/=>", NUMBER, BASE);
int i; /* we use int here as size_t is unsigned and we could
* not detect the loop exit condition */
for (i = N-1; i >= 0; i--) {
printf(" %u", r[i]);
}
printf("\n");
exit(EXIT_SUCCESS);
}
it shows:
$ pru
150000 =/base 38/=> 0 0 0 0 0 0 2 27 33 14
$ _

Function to count the sum of an array

Right, this is (the last) assignment for my C introduction web class.
The assignment presents the main program, does not explain anything about it and tells you to write a function to print and sum the array in it.
However I don't really understand what is going on in the main program.
Translated for your convenience;
Source code:
#include <stdio.h>
#include <stlib.h>
void print_count(int *, int);
int main(int argc, char *argv[]) {
int x, sum = 0, size = 0, array[5];
if (argc == 6) {
/* Program name and parameters received from command line */
for (x = 0; x < argc - 1; x++) {
array[x] = atoi(argv[x + 1]);
}
print_count(array, size);
} else {
printf("Error\n");
}
return 0;
}
Now I am completely clueless as to how to start writing the program requested and what variables to call/how to write the function.
Edit3: completed exercise
void print_count(int *array, int size) {
int i;
int sum = 0;
printf("Elements: ");
for (i = 0; i <= size; i++) {
printf("%d ", (array[i]);
sum = sum += array[i]);
}
printf("\nSum = %d ", sum);
return 0;
}
I would like to understand what is going on in the main program and preferably come to an answer on how to actually write the function by myself.
This:
array[5] = atoi(argv[x+1]);
is clearly wrong, it always tries to assign to array[5] which is out of bounds. It should be:
array[x] = atoi(argv[x + 1]);
This converts the x + 1:th argument from string format into an integer, and stores that in array[x]. If you're not familiar with the standard function atoi(), just read the manual page.
So if you start the program like this:
./myprogram 1 2 3 4 5
That has 6 arguments (the first is the name itself), and will end up with array containing the numbers one through five.
Then in the summing function, the first line should be something like:
void print_count(int *array, int size)
so that you give names to the arguments, which makes them usable in the function. Not providing names is an error, I think.
And it doesn't need to "interact" with main() more than it already does; main() calls print_count(), passing it a pointer to the first element of array and the length of the array, that's all that's needed to compute the sum.
Your print_count function has a few issues:
The loop runs one step too far: i should vary between 0 and size-1 included. The standard idiom for this loop is:
for (i = 0; i < size; i++) {
...
Incrementing sum is simply done with:
sum += array[i];
There is an extra ( on the first printf line.
You should print a newline after the output.
Returning 0 from a void function is invalid.
Here is a corrected version:
void print_count(int *array, int size) {
int i;
int sum = 0;
printf("Elements: ");
for (i = 0; i < size; i++) {
printf("%d ", array[i]);
sum += array[i]);
}
printf("\nSum = %d\n", sum);
}
the following proposed code:
cleanly compiles.
explains what is being accomplished at each step of the 'main()' function.
properly outputs error messages to 'stderr'.
implements the typical method to announce an error in the number of command line parameters.
Now the proposed code with explanatory comments:
#include <stdio.h> // printf(), fprintf()
#include <stdlib.h> // atoi(), exit(), EXIT_FAILURE
void print_count(int *, int);
int main(int argc, char *argv[])
{
if (argc != 6)
{
fprintf( stderr, "USAGE: %s int1 int2 int3 int4 int5\n", argv[0] );
exit( EXIT_FAILURE );
}
// implied else, correct number of arguments
// only declare variables when they are needed
int array[5];
// place each command line parameter into 'array',
// except program name
// I.E. skip the program name in argv[0]
for( int i = 1; i < argc; i++ )
{
// array[] index starts at 0, but loop counter starts at 1
array[i-1] = atoi(argv[i]);
} // end for( each value pointed at by argv[], except program name )
// print sum of command line parameters to stdout
int size = argc-1; // number of command line parameters after program name
print_count(array, size);
return 0;
} // end function: main

C programming find length of 2 Dimensional array

My program grabs command line arguements with argc and argv[]. My question is how can I find the length of argv[1][i].
My code that grabs length of argv[]
int my_strlen(char input[]){
int len = 0;
while(input[len] != '\0'){
++len;
}
return len;
}
but when I try to find argv[1][len] I get a subscripted value is neither array nor pointer:
my attempt
int my_strlen(char input[]){
int len = 0;
while((input[1][len] - '0') != '\0'){
++len;
}
return len;
}
FULL CODE:
#include <stdio.h>
#include <math.h>
int my_strlen(char input[]);
int main(int argc, char *argv[]){
int length = 0;
length = my_strlen(argv[1]);
long numberArr[length];
int i, j;
for(i = 0; i < length; i++){
numberArr[i] = argv[1][i] - '0';
}
return 0;
}
int my_strlen(char input[]){
int len = 0;
while((input[1][len] - '0') != '\0'){
++len;
}
return len;
}
Thanks for any help in advance!
I think you're confused about the argv content. The OS will pass a number of ASCIIZ strings, such that invoking my_program with arguments ala...
my_program first second third
...is similar to having the following declaration in your program...
int argc = 4;
const char* argv[4] = { "my_program", "first", "second", "third" };
Hence, when you index into argv[1][i] you're getting the i-th character in the string "first". That's only valid for values of i between 0 (which yields 'f'), and 5 (which indexes to the terminating NUL character '\0').
So, there no two-dimensional N*M array, but there is an array of pointers-to-(array-of-char). You can invoke the normal strlen() function as in strlen(argv[1]) to find out the number of characters in each argument. Only argc tells you the total number of elements in argv.
Does that help?
In main, you're passing argv[1] to my_strlen. That means my_strlen just receives a normal, single-dimension string. It doesn't need to do input[1][len], just input[len].

Resources