Null pointer passed as argument 1 - c

In line int d = atoi(argv[2]); there seems to be something wrong. "null pointer passed as argument 1..."
What can I do?
#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, string argv[])
{
int num;
int i = 1;
int j = 1;
int board [i][j];
// 2nd CL argument is size of grid.
if (argc != 2)
{
return false;
}
int d = atoi(argv[2]);
if (d <= 0)
{
return false;
}
// setting up board.
// number of tiles needed.
num = d * d - 1;
// iterating over columns and rows
for (i = 0; i <= d; i++)
{
for (j = 0; j <= d; j++)
{
// set values.
board[i][j] = num;
num --;
}
printf ("%d", board[i][j]); // TESTING.
printf ("\n");
}
// if even swap 1 & 2. Don't display 1.
}

argv[0] holds the name of the command used to start your program. If you expect two command line arguments, check argc == 3 and read the command line arguments from argv[1] and argv[2].

You have a multiple issues with your program
1) string is not a standard type in C.
2) false is not a standard constant in C98.
Standard C (since C99) provides a boolean type, called _Bool. By including the header stdbool.h one can use the more intuitive name bool and the constants true and false.
3) Your board has a fixed size 1x1 board[1][1]:
int i = 1;
int j = 1;
int board [i][j];
Fix this otherwise your program will smash memory.
4) You need 2 arguments for your board. Arguments start on position argv[1] and argv[2] in argv[] Since first argv[0] is name of the program you need argc = 3.

Related

Factorial program displaying the inital value and not the factorial itself

Below is my program to calculate the factorial of a given int. It compiles but only displays the initial value of the fact. It most likely has something to do with the if(argc>1) statement, but that is required for the assignment.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* aragv[])
{
int fact = 1;
int n = atoi(char* aragv[]);
if(argc>1)
{
for(int i = 1; i < n ; i++)
{
n = n * i;
}
}
printf("%d\n", fact);
return 0;
}
Heavily commented code :
#include <stdio.h>
#include <stdlib.h>
#define USAGE "USAGE: ./program [+ve number upto 20]" // define constants & repetitive texts
int main(int argc, char* argv[]) // argc & argv have universal appeal
{
//int fact = 7; // use larger integer
unsigned long int factorial = 1; // 0! = 1
//if(argc>1) // instead check program is run with an argument
if (argc != 2) { // invalid program run
printf ("\n\t%s\n", USAGE);
return 1; // return non-zero to indicate error to caller
}
int number ; //= atoi (argv[1]); // convert string to integer; number is in argv[1]
// #DavidC.Rankin correction
if (sscanf (argv[1], "%d", &number) != 1) { // to make sure we read "a number"
printf ("\n\tERROR: Invalid Number [%s]\n\t%s\n", argv[1], USAGE);
return 3;
}
if (number > 20 || number < 0) { // long int (64 bits) can't store more than 20!
printf ("\n\tERROR: [%d] Out of valid range [0 to 20]\n\t%s\n", number, USAGE);
return 2; // different number for different scenarios
}
for (int i = 2; i <= number; i++) // you can skip 1 as doesn't make a difference
factorial = factorial * i;
printf("\nAnswer:\t %d! = %lu\n", number, factorial); // %lu for unsigned long int
return 0;
}
When you're learning, it always helps if you learn in increments.

Is it possible to decide the level of indirection of a pointer at runtime using C?

Is it possible to declare a pointer-to-pointer-to-...-to-[data type] whose level of indirection is decided at runtime?
This is a thought experiment; I am aware that this is probably awful practice and I have no intentions of actually using it for anything. But I spent several hours thinking about it and abusing preprocessor macros and came up empty, so I'm curious if someone can figure out how to do this:
Write a program that takes as input an int m (up to 255) from stdin and declares an m-level-indirected pointer to int. i.e. if the input is 4, it should declare int ****x; in the top level scope of main().
You cannot change declarations at runtime. But you could do something like:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int
main(int argc, char **argv)
{
int count = argc > 1 ? strtol(argv[1], NULL, 0) : 5;
int d = argc > 2 ? strtol(argv[2], NULL, 0) : 10;
void *f[10];
int dereferenced;
if( count > 5 ) {
fprintf(stderr, "levels of direction must be <= 5\n");
exit(EXIT_FAILURE);
}
f[0] = &d;
for(int i = 1; i < 10; i++) {
f[i] = f + i - 1;
}
switch(count) {
case 1:dereferenced = *(int *)f[0];
case 2:dereferenced = **(int **)f[1];
case 3:dereferenced = ***(int ***)f[2];
case 4:dereferenced = ****(int ****)f[3];
case 5:dereferenced = *****(int *****)f[4];
}
printf ("%d\n", dereferenced);
}

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

Pointers aren't being transferred to allocated memory

I have a school assignment, and everything works just fine except for one part, which I cannot figure out. The following is the snippet of code where my issue is occurring:
//something goes wrong here, wont copy over
puts("bravo");
//add to end of the list
int size_list = sizeof(environ);
//char** tmp_ptr = ( char** )calloc( size_list + 1, ( size_list + 1 ) * sizeof( char* ) );
char** tmp_ptr = ( char** ) malloc ( ( size_list + 1 ) * sizeof( char* ) );
int k;
for ( k = 0; k < size_list; ++k )
{
tmp_ptr[k] = environ[k];
//memcpy(tmp_ptr[k],environ[k],sizeof(environ[k]));
}
//char** tmp_ptr= (char**)realloc(*environ, size_list+2);
environ = tmp_ptr;
environ[size_list] = (char*)malloc(len_string+1);
strcpy(environ[size_list],full_string);
return 1;
You can ignore the "bravo", it was for me to locate where the problem was occurring. I am trying to get environ to have the new list of variables, but when I set it equal to tmp_ptr, it is empty. I'm pretty sure that the values are getting copied over, but I do not know what is wrong.
Does the data in tmp_ptr get deleted when the function ends? Is that a possible explanation? How can I properly allocate and copy over the memory. I tried using realloc, but that gave me invalid pointer errors, so I am relying on calloc or malloc. Thanks in advance.
environ's length isn't sizeof(environ), since environ is a char ** (and thus sizeof(environ) is 4 or 8 depending on your platform). What you're doing is effectively wiping out most of environ because you only copy the first few entries.
To find out how many entries are in environ, do
int cnt = 0;
char **envp = environ;
while(*envp++) cnt++;
I should also note a problem with the approach: since environ is a NULL-terminated string array (not to be confused with 'null-terminated string'), you have to replace the NULL at the end with your own entry, then add a new NULL after your new entry. Currently, your code (if it calculated the size correctly) would have added your entry after the NULL, and would have not been visible to the program.
Side note: messing with environ this way is definitely not recommended. Use getenv/setenv instead; if you need to mass-set the environment, try using execve instead. (So, in your case, you can simply setenv("varname", "varvalue", 1) to add varname=varvalue to the environment (and replace an existing mapping to varname if it is already set).
environ is a pointer, meaning that sizeof(environ) is not the number of items in that array. Rather, it's the size of the pointer, probably four or eight in your case.
If environ is the same sort of structure as argv (an array of character pointers where the last one is a null pointer), you will need to determine its size by walking through the array until you find NULL.
Something like (untested, but the idea is sound):
char **envPtr = environ;
int size_list = 0; // probably should be size_t
while (*envPtr != NULL) {
envPtr++;
size_list++;
}
You can see the effect in this complete program (with a few changes to get around some other bugs):
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define full_string "xyzzy=plugh"
#define len_string strlen(full_string)
int main (int argc, char **argv) {
int k, size_list = sizeof(environ);
char **tmp_ptr = malloc ((size_list + 1) * sizeof ( char*));
for (k = 0; k < size_list; ++k) printf ("[%s]\n", environ[k]);
for (k = 0; k < size_list; ++k) tmp_ptr[k] = environ[k];
tmp_ptr[size_list] = NULL;
environ = tmp_ptr;
environ[size_list] = malloc (len_string + 1);
strcpy(environ[size_list],full_string);
printf ("=====\n");
for (k = 0; k <= size_list; ++k) printf ("[%s]\n", environ[k]);
return 0;
}
This outputs only four of my environment variables because I have four-byte pointers:
[ORBIT_SOCKETDIR=/tmp/orbit-pax]
[SSH_AGENT_PID=1978]
[GPG_AGENT_INFO=/tmp/seahorse-tNDhG9/S.gpg-agent:2005:1]
[TERM=xterm]
=====
[ORBIT_SOCKETDIR=/tmp/orbit-pax]
[SSH_AGENT_PID=1978]
[GPG_AGENT_INFO=/tmp/seahorse-tNDhG9/S.gpg-agent:2005:1]
[TERM=xterm]
[xyzzy=plugh]
Changing the code to correctly determine the size of the environment:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define full_string "xyzzy=plugh"
#define len_string strlen(full_string)
int main(int argc, char **argv) {
int k, size_list = 0;
char **envPtr = environ;
while (*envPtr != NULL) {
envPtr++;
size_list++;
}
char **tmp_ptr = malloc ((size_list + 1) * sizeof (char*));
for (k = 0; k < size_list; ++k) printf ("[%s]\n", environ[k]);
for (k = 0; k < size_list; ++k) tmp_ptr[k] = environ[k];
tmp_ptr[size_list] = NULL;
environ = tmp_ptr;
environ[size_list] = malloc (len_string + 1);
strcpy(environ[size_list],full_string);
printf ("=====\n");
for (k = 0; k <= size_list; ++k) printf ("[%s]\n", environ[k]);
return 0;
}
gives me the lot:
[ORBIT_SOCKETDIR=/tmp/orbit-pax]
[SSH_AGENT_PID=1978]
[GPG_AGENT_INFO=/tmp/seahorse-tNDhG9/S.gpg-agent:2005:1]
[TERM=xterm]
[SHELL=/bin/bash]
[GTK_RC_FILES=/etc/gtk/gtkrc:/home/pax/.gtkrc-1.2-gnome2]
[WINDOWID=62914564]
[GNOME_KEYRING_CONTROL=/tmp/keyring-RADe9n]
[GTK_MODULES=canberra-gtk-module]
[USER=pax]
:
[XAUTHORITY=/var/run/gdm3/auth-for-pax-AO1dYc/database]
[_=./testprog]
=====
[ORBIT_SOCKETDIR=/tmp/orbit-pax]
[SSH_AGENT_PID=1978]
[GPG_AGENT_INFO=/tmp/seahorse-tNDhG9/S.gpg-agent:2005:1]
[TERM=xterm]
[SHELL=/bin/bash]
[GTK_RC_FILES=/etc/gtk/gtkrc:/home/pax/.gtkrc-1.2-gnome2]
[WINDOWID=62914564]
[GNOME_KEYRING_CONTROL=/tmp/keyring-RADe9n]
[GTK_MODULES=canberra-gtk-module]
[USER=pax]
:
[XAUTHORITY=/var/run/gdm3/auth-for-pax-AO1dYc/database]
[_=./testprog]
[xyzzy=plugh]
For what it's worth, your code had the following problems:
The incorrect calculation of the environment size, obviously.
Casting the return value from malloc - this is ill-advised in C since it can cause code problems to be hidden from you.
Not setting the final element of the new list to NULL.
Not checking for out-of-memory conditions.
All these except the last are fixed in my final code sample above.

Resources