Pointers & Dynamic Memory Allocation in C - c

I'm fairly new to the language C and am getting a bit muddled up with pointers & dynamic memory allocation. What I'm trying to do is read in command line arguments and store them in dynamic memory allocation; then printing them out. For example if I typed ./rpd 4 3 2 3 8 then argv[1] (4) should be decremented and the other 3 values (3, 2, 3, 8) should follow. The output should look like:
Person 1 has 3 cars.
Person 2 has 2 cars.
Person 3 has 3 cars.
Person 4 has 8 cars.
My Code is:
#include <stdio.h>
int main(int argc, char *argv[]) {
/** argc is number of arguments at command line*/
/** argv[] is an array of pointers to character strings
i.e. argv 1 points to argc 1 */
int numberOfCars;
char *person;
int i;
int j;
// Allocate the size of the array for each element of char
person = malloc(sizeof(numberOfCars) *argc);
for(i = 2; i < argc; i++) {
/** Convert char to int */
numberOfCars = atoi(argv[i]);
person = atoi(argv[1]);
if(person > 0){
for(j = 2; j < person; j--) {
printf("Person %d has %d cars \n", person--, numberOfCars);
}
} else {
/** DO NOTHING */
}
}
return person;
}
I'm sorry if this is a little confusing (or naive) of me; but I am extremely new to this language so I'm still trying to get my head around everything.
Thanks alot for any help :)

Try something like this:
#include <stdio.h>
int main(int argc, char *argv[]) {
/** argc is number of arguments at command line*/
/** argv[] is an array of pointers to character strings
i.e. argv 1 points to argc 1 */
int numberOfCars;
int i;
for(i = 1; i < argc; i++) {
/** Convert char to int */
numberOfCars = atoi(argv[i]);
printf("Person %d has %d cars \n", i, numberOfCars);
}
return 0;
}
Then tweak it for your needs. You dont need to specify the number of people for the first input argument, since it's implied by the number of cars you specify for each person.

Code
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int numberOfCars;
int *person;
int i;
person = malloc(sizeof(int) * argc);
for(i = 1; i < argc; i++)
{
numberOfCars = atoi(argv[i]);
if (i == 1)
numberOfCars--;
person[i] = numberOfCars;
printf("Person %d has %d cars\n", i, numberOfCars);
}
free(person);
return 0;
}
Sample output
$ ./rpd 4 3 2 3 8
Person 1 has 3 cars
Person 2 has 3 cars
Person 3 has 2 cars
Person 4 has 3 cars
Person 5 has 8 cars
$
Explanation
#include <stdio.h>
#include <stdlib.h>
You need <stdlib.h> to declare malloc() and free(). When you use malloc(), you should also use free().
int main(int argc, char *argv[])
{
int numberOfCars;
int *person;
int i;
The variable j is unused in the revision and therefore removed. The variable person is changed to int * as person[i] will store the number of cars person i has.
person = malloc(sizeof(int) * argc);
I changed the sizeof() to int; it would also be possible to use sizeof(*person) and there are good reasons for preferring that.
for (i = 1; i < argc; i++)
{
numberOfCars = atoi(argv[i]);
The assignment person = atoi(argv[1]); was erroneous at multiple levels. It leaked the memory assigned by the malloc(); it assigned an int to a pointer (originally a char *).
if (i == 1)
numberOfCars--;
This deals with the 'subtract one from first argument' requirement.
person[i] = numberOfCars;
This records the number of cars that person i has. It isn't used; it could be used in place of numberOfCars in the printf() statement.
printf("Person %d has %d cars\n", i, numberOfCars);
Spaces at the end of a line are a bĂȘte noire of mine. Don't put blanks before a newline.
}
free(person);
Release the memory that was allocated. In this toy program, it isn't critical (the o/s is about to release all the resources used by the program), but if it was a function in a big program and it omitted the free(), it would leak memory each time it is called. Get into the habit of writing the free() for each malloc() as soon as you've written the malloc(). (Or, at least, make sure you know where you will write the free(), and do write the free() before compiling, let alone testing, the program.)
return 0;
}

What do you want to store dynamically?
If want to only print the values as you mentioned in question. You would not require dynamic allocation at all.
If at all you want to store them use
char **person; //instead of *person and keep allocation memory per person by using
person[i] = malloc(sizeof(argv[i])+sizeof("person has cars")); //not sure of ur required format to store you can change it accordingly

atoireturns an int, but person is a char pointer.
#include <stdio.h>
int main(int argc, char *argv[]) {
/** argc is number of arguments at command line*/
/** argv[] is an array of pointers to character strings
i.e. argv 1 points to argc 1 */
int numberOfCars;
int i;
int p = 0;
for(i = 2; i < argc; i++) {
/** Convert char to int */
numberOfCars = atoi(argv[i]);
printf("Person %d has %d cars \n", ++p, numberOfCars);
}
return 0;
}
Output:
$ ./a.out 4 3 2 3 8 10
Person 1 has 3 cars
Person 2 has 2 cars
Person 3 has 3 cars
Person 4 has 8 cars
Person 5 has 10 cars

Related

scanf is not storing the full set of each line but is stopping at each period and then starting storing from a new line

i am tring to read in a series of network addresses similar to
168.12.110.25
64.113.134.35
217.158.91.183
102.130.129.146
215.116.26.223
81.162.78.0
19.204.25.222
245.124.138.157
137.249.183.201
106.61.236.67
106.71.236.60
106.81.240.63
168.14.111.27
168.17.111.27
215.116.26.220
137.249.111.202
137.246.111.202
and store them into netoworks, that has to be a two dimensional array.
//declare libraries
#include <stdio.h>
#include <stdlib.h>
//declare other functions/files to be used in the program
void print_fun(void);
int sort_fun(void);
void read_fun(void);
//read command line input and store the information
int main(int argc, char** argv){
unsigned char networks[argc][4];
int arg = 0;
//convert command line argument to int
arg = atoi(argv[1]);
for (int j =0; j<1; ++j){
if(argc == 1)
{
printf("ERROR ERROR, you messed up\n");
}
else
{
// hold network addresses in a 2-d array, with 4 unsig char
for(int k = 0; k<arg; ++k){
for (int i =0; i<4; ++i){
scanf("%hhu",&networks[k][i]);
printf("%hhu",networks[k][i]);
}
printf("\n");
}}}
//sort array
42 //count networks
//print info about the array
}
i am wondering what i am doing wrong. i need to store the information coming in from the file into networks, the scanf is not storing the complete information of each address.
the new output
[p18d541#csci112 program1]$ ./main 17 < inp17.txt
1680640
0000
11000
0000
2481141048
25512700
194000
2000
2311131048
25512700
2919640
17000
1601131048
25512700
1000
0000
20818640
how do i change my code to store the network properly.
EDIT
with a quick update to the code of adding a period on the scan and print.
//declare libraries
#include <stdio.h>
#include <stdlib.h>
//declare other functions/files to be used in the program
void print_fun(void);
int sort_fun(void);
void read_fun(void);
//read command line input and store the information
int main(int argc, char** argv){
unsigned char networks[argc][4];
int arg = 0;
//convert command line argument to int
arg = atoi(argv[1]);
for (int j =0; j<1; ++j){
if(argc == 1)
{
printf("ERROR ERROR, you messed up\n");
}
else
{
// hold network addresses in a 2-d array, with 4 unsigned char
for(int k = 0; k<arg; k++){
for (int i =0; i<4; i++){
scanf("%hhu.", &networks[k][i]);
printf("%hhu.\",networks[k][i]);
}
printf("\n");
}}}
//sort array
//count networks
//print info about the array
}
and the new output is,
[p18d541#csci112 program1]$ ./main 17 < inp17.txt
1681211025
6411313435
21715891183
102130129146
21511626223
81162780
1920425222
245124138157
137249183201
1066123667
1067123660
1068124063
Segmentation fault (core dumped)
or it has thousands of output.
it is random
scanf is having a hard time parsing the periods between the numbers, and it's causing it to behave in unexpected ways. Try this instead:
scanf("%hhu.",&networks[k][i]);
printf("%hhu",networks[k][i]);
You've also got an issue in your declaration of array size:
unsigned char networks[argc][4];
argc is how many arguments were passed into the function, not the actual value you passed. This means your array is going to be the wrong size, likely resulting in a segfault. Try this instead:
int arg = 0;
//convert command line argument to int
arg = atoi(argv[1]);
//declared AFTER we have the value we want
unsigned char networks[arg][4];

Printing array of struct Segmentation fault

I'm trying to print my struct. I want it to show:
id: BBB-188
brand: BMW
pic: 1 2 3.
Right now the result is this:
id: BBB-188
name: BMW
Segmentation fault: 11.
Does anyone know what is wrong with my code?
#define MAX 10000
#define IDSIZE 11
#define BRANDSIZE 50
#define PICSIZE 10
typedef struct{
char id[IDSIZE+1];
char brand[BRANDSIZE+1];
int *pic;
} Car;
void printCar(Car *pCar,int carcount, int imagecount) {
printf("id: %s \n",pCar->id);
printf("brand: %s \n",pCar->brand);
for(int i=0; i< imagecount; i++){
printf("pic: %d \n",pCar->pic[i]);
}
}
Car initCar(char itsId[],char itsBrand[],int itsPic, int imagecount){
Car newCar;
strcpy(newCar.id, itsId);
strcpy(newCar.brand, itsBrand);
for (int i = 0; i < imagecount; i++){
newCar.pic = itsPic;
}
return newCar;
}
int main(void){
int carcount=0;
int imagecount=0;
int test[3]={1,2,3};
Car myCar = initCar("BBB-188","BMW", test, 3 );
carcount=1;
imagecount=3;
printCar(&myCar,carcount,imagecount);
return 0;
}
The handling of pic is broken and very confusing.
You seem to want to represent it as an array of integers, but you don't store the length. Thus it has to be always three, but then you can just use an array in the structure, i.e.:
int pic[3];
instead of
int *pic;
Also the assignment inside initCar() makes no sense, you're looping but simply assigning the same integer value (!) to the pointer imagecount times, no data is being copied.
If you want the length of the picture array to really be variable, you must store the length and allocate memory for holding the numbers. So in initCar() you must have:
newCar.pic = malloc(imagecount * sizeof *newCar.pic);
memcpy(newCar.pic, itsPic, imagecount * sizeof *newCar.pic);
but then itsPic must of course be of type const int *.
You need to pass itsPic as a pointer in initCar. If you're doing so, you don't need the for loop for the affectation.
Car initCar(char itsId[],char itsBrand[],int* itsPic, int imagecount){
Car newCar;
strcpy(newCar.id, itsId);
strcpy(newCar.brand, itsBrand);
//for (int i = 0; i < imagecount; i++){
newCar.pic = itsPic;
//}
return newCar;
}

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 converting character command line arguments to an integer array

I'm new to C and trying to figure out arrays and command line arguments. I have:
int main(int argc, int **argv) {
int vals[8];
for(int i = 0;i < 8;i = i + 1) {
vals[i] = atoi(argv[i]);
printf("%d", vals[i]);
}
}
I call it with ./file 1 2 3 4 5 6 7 8 and I would expect it to spit out 12345678, but instead, it spits out 01234567 which to me says that it's just printing the array positions. How do I get to actually print/access the value of vals[i], and/or make sure that the command line value is actually being properly assigned?
Thanks in advance.
Start with argv[1] In order to exclude the first element of argv which is the program name. A simple way to do this is to increment argv at the top of the program.
int main(int argc, char **argv) {
argv++; /* argv[0] is the program name */
int vals[8];
for(int i = 0;i < 8;i = i + 1) {
vals[i] = atoi(argv[i]);
printf("%d", vals[i]);
}
}
On a side note, you should check the value of argc prior to accessing elements at index i in argv
argv [0] is the name of the program.
The arguments start at 1. You should also get in the habit of using argc in loops.
int main(int argc, int *argv[])
{
for(int i = 1 ; i < argc ; ++ i )
{
int val = atoi(argv[i]);
printf("%d", val);
}
}

Parse arguments into an array

I am trying to create a simplified version of the Rummy card game. I need to parse in the card abbreviations for example SA is Spades Ace. DT is Diamond 10 etc. I know there is an easier way to do this but that's how my assignment wants it done.
The sample execution would look like
rummy 3 S2 H9 C4... etc. include all 52 cards.
The number in argv[1] is the players in the game. How am I supposed to take the cards starting after the number and put them into an array?
My code so far
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int players = *argv[1];
char deck[52];
int i, j, pid, cid;
if (players > '5' || players < '3')
{
printf("%c is not the allowed number of players, min is 3 and max is 5\n",*argv[1]);
exit(0);
}
}
Quick and dirty demonstration:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int players = atoi(argv[1]);
char deck[52][3];
int i, j, pid, cid;
if (players > 5 || players < 3)
{
printf("%d is not the allowed number of players, min is 3 and max is 5\n", players);
exit(0);
}
for (i = 0; i < argc - 2; i++)
{
strcpy(deck[i], argv[i+2]);
}
for (i = 0; i < argc - 2; i++)
{
printf("%s\n", deck[i]);
}
}
Absolultely no sanity checks are done concerning the input. It's just for demonstration.
Your int argc is the count of arguments. So you can indeed manually load all of these cards into an array if you so choose.
Assuming you execute the program like this:
example.exe rummy 3 S1 S2 S3 S4 A1 A2 A3 A4
You could then read the cards into an array like this (assuming that "rummy" is game type and "3" is some other control variable, you need to make sure of this)
int main(int argc, char *argv[])
{
char game[10] = argv[0];
int players = atoi(argv[1]);
char deck[52][3]; // an array of strings max lenght 3 (2 characters + required '\0' terminator
for (int i = 0; i < argc - 2; i++) // argc - 2 because we're accessing at i+2 so the last iteration will essentially access the last element
{
strcpy(deck[i], argv[i+2]); // copy into actual array
}
return 0;
}
Now you got your cards in an array of char arrays called deck. Take note that this is completly only a sample and that it is not recommended for direct use. In an eventual program you must have sanity checks and validation against all possible cases (too many args, too little args, wrong args, etc.
All arguments passed on command line are stored in argv array. argv[0] is always the name of the program and next come your arguments if any (as null-terminated strings).
So assuming you have called this as:
rummy 3 S2 H9 C4
this is what argv contains:
argv[0] = "rummy"
argv[1] = "3"
argv[2] = "S2"
argv[3] = "H9"
argv[4] = "C4"
Inserting these into array is simple:
char args[5][10];
strncpy(args[0], argv[0], 10);

Resources