Strange out of scope variable - c

I was looking up the getopt command and I discovered that using the function seems to inexplicably produce another variable called optarg. You can see an example of this in the following program I swiped from Wikipedia:
#include <stdio.h> /* for printf */
#include <stdlib.h> /* for exit */
#include <unistd.h> /* for getopt */
int main (int argc, char **argv) {
int c;
int digit_optind = 0;
int aopt = 0, bopt = 0;
char *copt = 0, *dopt = 0;
while ( (c = getopt(argc, argv, "abc:d:012")) != -1) {
int this_option_optind = optind ? optind : 1;
switch (c) {
case '0':
case '1':
case '2':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;
case 'a':
printf ("option a\n");
aopt = 1;
break;
case 'b':
printf ("option b\n");
bopt = 1;
break;
case 'c':
printf ("option c with value '%s'\n", optarg);
copt = optarg;
break;
case 'd':
printf ("option d with value '%s'\n", optarg);
dopt = optarg;
break;
case '?':
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc) {
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}
exit (0);
}
Notice that optarg is now being used seemingly without be declared or initialized. Maybe this is just a common feature in C that I am unaware of, but I have been googling for a few hours and I don't know the name of what I am looking for. Any explanations would be nice.

The term is "global variable". If you declare a variable outside of a function, it's accessible inside functions:
int i = 7;
int main()
{
printf("%d\n", i); // prints 7
return 0;
}
In the case of optarg, the unistd.h header declares it as a global char * variable with external linkage:
extern char *optarg;
(see http://pubs.opengroup.org/onlinepubs/000095399/functions/getopt.html).

From the man page
GETOPT(3) BSD Library Functions Manual GETOPT(3)
NAME
getopt -- get option character from command line argument list
LIBRARY
Standard C Library (libc, -lc)
SYNOPSIS
#include <unistd.h>
extern char *optarg;
extern int optind;
extern int optopt;
extern int opterr;
extern int optreset;
int
getopt(int argc, char * const argv[], const char *optstring);
These variables are declared in the unistd.h header file.

For future reference, if you find names but don't know where they are defined or declared, only run the C pre-processor, which is responsible for #include, and then search for the term using grep or just more.
For example
gcc -E foo.c >foo.i
would put the result of the C pre-processor into foo.i
You could then have a look at the file using more (using / to search)
The file will have references to the include file which includes the definition or declartion.
For example,
more foo.i
then
/optarg
shows the line
extern char *optarg;
by scrolling upwards (or reverse search ?# ) I could find
# 414 "/usr/include/unistd.h" 3 4

optarg is declared in <unistd.h>.

— Variable: char * optarg
This variable is set by getopt to point at the value of the option argument, for those options that accept arguments.
I find this at the Using Getopt websit

Related

How to read and then print an array of strings in C?

I'm trying to read the following type of input
2
string1
string2
where the first line indicates the amount of strings following below, and the strings are all of (some) same length. Next, I'd like to print these strings in my program, which I was thinking of doing as follows.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void print_string_array(char** a, int size){
for (int i=0; i<size; i++){
printf("%s\n", a[i]);
}
}
int main()
{
int n;
scanf("%d", &n);
char* s;
scanf("%s", s);
int l = strlen(s);
char input[n][l];
strcpy(s, input[0]);
for (int i = 1; i < n; i++) {
scanf("%s", s);
strcpy(s, input[i]);
}
print_string_array(input, n);
}
But I get the following warnings and error.
main.c: In function ‘main’:
main.c:24:24: warning: passing argument 1 of ‘print_string_array’ from incompatible pointer type [-Wincompatible-pointer-types]
24 | print_string_array(input, n);
| ^~~~~
| |
| char (*)[(sizetype)(l)]
main.c:5:32: note: expected ‘char **’ but argument is of type ‘char (*)[(sizetype)(l)]’
5 | void print_string_array(char** a, int size){
| ~~~~~~~^
Segmentation fault (core dumped)
Why isn't my array input recognized as a char** type? And how would I go about fixing this without removing the general properties of my current program (for example, adaptability to any length of input strings)?
EDIT:
I've corrected some mistakes from not having coded in C for years (which may be a war crime from what I've seen in the comments):
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void print_string_array(char** a, int size){
for (int i=0; i<size; i++){
printf("%s\n", a[i]);
}
}
int main(){
int n;
scanf("%d", &n);
char s[100]; // large enough buffer
scanf("%s", s);
int l = strlen(s);
char input[n][l+1]; // +1 to leave room for ‘\0’ character?
strcpy(input[0], s);
for (int i=1; i<n; i++){
scanf("%s", input[i]);
}
print_string_array(input, n);
for (int i=0; i<n; i++){
free(input[i]);
}
free(input);
}
But I still get some errors and warnings which I would like to solve.
main.c: In function ‘main’:
main.c:22:24: warning: passing argument 1 of ‘print_string_array’ from incompatible pointer type [-Wincompatible-pointer-types]
22 | print_string_array(input, n);
| ^~~~~
| |
| char (*)[(sizetype)(n)]
main.c:5:32: note: expected ‘char **’ but argument is of type ‘char (*)[(sizetype)(n)]’
5 | void print_string_array(char** a, int size){
| ~~~~~~~^
Segmentation fault (core dumped)
Starting with the warnings, obviously I change the type of a from char** to something else. However, should I really give it the type char (*)[(sizetype)(n)]?? Also, there's the problem of segmentaion fault which is happening somewhere in the for loop.
Besides the problems in your code that are explained in the comments.
input is a char* that points to an array in memory that is of size n*l and not a char**, which is a pointer to a char*.
You would need to allocate an array of char*[] and then add each char* pointer that you get from scanf to that array.
The Variable Length Array input[n][l+1] does not need to be free'd.
The input[n][l+1] array is not a pointer to pointer **a. There are differences in the memory arrangement and they are not compatible.
void print_string_array( int size, int len, char (*a)[len]){ gives the compiler the dimensions of the VLA so the function can access it correctly.
scanf("%99s", s); will limit the input to no more than 99 characters. There is a problem in limiting input in scanf("%s", input[i]); to avoid putting too many characters into input[i].
#include <stdio.h>
#include <string.h>
void print_string_array( int size, int len, char (*a)[len]){
for (int i=0; i<size; i++){
printf("%s\n", a[i]);
}
}
int main(){
int n;
scanf("%d", &n);
char s[100]; // large enough buffer
scanf("%99s", s);
int l = strlen(s);
char input[n][l+1]; // +1 to leave room for ‘\0’ character?
strcpy(input[0], s);
for (int i=1; i<n; i++){
scanf("%s", input[i]);
}
print_string_array(n, l + 1, input);
}
Maybe this will help you out. It shows an example of dynamic string allocation
char buffer[101];
printf("Enter your name: ");
// Stores the name into auxiliary memory
scanf(" %100[^\n]", buffer);
// Creates a dynamic string
char* name = (char *) malloc(strlen(buffer) + 1);
//or use char* name = strdup(buffer) as pointed out by #Cheatah in the comments
// Sets the value
strcpy(name, buffer);
printf("Your name is %s", name);
// Frees the memory
free(name);
If you are just to print the strings one after the other, as you receive them, there's no need to store the full set of strings (or even a complete string) to do the task, you can implement a simple (4 states) automaton to read the number of strings, then print the strings as you are receiving their characters (character by character). This allows you to handle any length strings (like hundreds of megabyte strings) and upto 4,294,967,295 strings. (more if I change the declaration of n) and you'll get a far more efficient program that starts printing as soon as possible, instead of reading everything before printing anything.
#include <stdio.h>
#include <stdlib.h>
#define IN_STRING (0)
#define AFTER_NUMBER (1)
#define IN_NUMBER (2)
#define PRE_NUMBER (3)
#define F(_fmt) "%s:%d:%s:"_fmt, __FILE__, __LINE__, __func__
#define ERR_TAIL(E_fmt, ...) do { \
fprintf(stderr, _fmt, ##__VA_ARGS__); \
exit(1); \
} while(0)
#define ERR(ERR_fmt, ...) \
ERR_TAIL(F("ERROR: "_fmt), ##__VA_ARGS__)
int main()
{
int c, /* to hold the char */
last_char = EOF, /* to hold the prvious char */
status = PRE_NUMBER; /* state of the automaton */
unsigned n = 0; /* number of strings to read */
while ((c = fgetc(stdin)) != EOF) {
switch (status) {
case PRE_NUMBER:
switch(c) {
case ' ': case '\n': case '\t':
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
status = IN_NUMBER;
n = c - '0';
break;
default: /* error */
ERR("Sintax error on input: non"
" digit character '%c' before "
"first number\n", c);
return 1;
} /* switch */
break;
case IN_NUMBER:
switch (c) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
n *= 10;
n += c - '0';
break;
case '\n':
status = IN_STRING;
break;
default:
status = AFTER_NUMBER;
break;
} /* switch */
break;
case AFTER_NUMBER:
switch (c) {
case '\n':
status = IN_STRING;
break;
case '\t': case ' ': /* ignored */
break;
default: /* error */
ERR("Sintax error on input: extra"
" character '%c' after first "
"number\n", c);
exit(1);
} /* switch */
break;
case IN_STRING:
switch (c) {
case '\n':
fputc(c, stdout);
if (!--n)
exit(0);
break;
default:
fputc(c, stdout);
break;
} /* switch */
break;
} /* switch */
last_char = c;
} /* while */
int exit_code = 0;
/* decide what to do when we receive a premature EOF */
switch(status) {
case PRE_NUMBER: /* before reading a number */
ERR("No number read before the strings\n");
exit_code = 1;
break;
case IN_NUMBER: /* in a number or in the spaces */
case AFTER_NUMBER: /* after the first newline */
fprintf(stderr,
"Nothing read after the number of strings\n");
exit_code = 1;
break;
case IN_STRING: /* IN_STRING, but */
if (last_char != '\n')
fputc('\n', stdout);
} /* switch */
return exit_code;
} /* main */
anyway, in your code:
char* s;
scanf("%s", s);
you cannot pass scanf() a pointer value that has not been initialized with enough memory to hold the string to be read.
On other side, beware that variable array declaracions (VAD) are controversial, as many compilers don't implement them and your code will not be portable, when you declare an array as VAD, you reserve space in the stack for the array, this being probably a mess if you end declaring very big arrays. The best and most portable way of declaring an array is to declare it with a constant expression (an expression that doesn't change at run time / an expression that is calculated by the compiler at compilation time) This is not your case, as you want to hold as big lines and as many as you like, with the only restriction that all the strings must have the same length as the first one (which you cannot enforce in any way)
One reason for the VADs being controversial is related to the following warning you have in your code
main.c:5:32: note: expected ‘char **’ but argument is of type ‘char (*)[(sizetype)(n)]’
5 | void print_string_array(char** a, int size){
| ~~~~~~~^
This informs you that a char ** is not the same type as a pointer to an array of n elements, on pointer decayment when passing it as parameter (the decayment happens only to the outer pointer, not to the inner ones). Decayment goes to the first level only, as the second/third/etc. are pointers to arrays, and so, the referred elements are not pointers, but arrays of n elements. When you increment a pointer char * or you do pointer arithmetic, you increment the address stored in that pointer variable by one because the pointed to type is an array. But when you increment a pointer char (*)[10] (a pointer to a ten element char array) you increment the address stored in that pointer by 10, so you cannot use pointer arithmetic, as you have declared it as a double pointer and it will be increased by sizeof (char *) (which is not what you want, 8 bytes, the size of a pointer)
Almost all the things commented lead you to Undefined Behaviour, and it is normal that you are getting that error. If I hade to write your code (and conserve the strings before doing anything) I would use dynamic memory with malloc(3) and realloc(3) as I parse the input.

Check for specific command line arguments and then assign them to variables

Obligatory total noob here.
I am making a simple C program that reads some variables from a file from a simple function.
What I'm trying to accomplish, however, is to allow whoever calls the program to override the values read from the file if hey so specify in the command line arguments.
I would like to have something like this:
char* filename;
int number;
...
readConfig(filename, number, ...);
if (argc > 1) {
// Check if the variables were in the args here, in some way
strcpy(filename, args[??]);
number = atoi(args[??]);
}
I would like the program to be called as
program -filename="path/to/file.txt" -number=3
I figured out I could just tokenize each argument and match it to every assignable variable and discard the others, but I'm pretty sure that there's a more elegant way to do this (perhaps with getopts?)
Thank you so much for your help.
I found this on geeksforgeeks:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int opt;
// put ':' in the starting of the
// string so that program can
//distinguish between '?' and ':'
while((opt = getopt(argc, argv, ":if:lrx")) != -1)
{
switch(opt)
{
case 'i':
case 'l':
case 'r':
printf("option: %c\n", opt);
break;
case 'f':
printf("filename: %s\n", optarg);
break;
case ':':
printf("option needs a value\n");
break;
case '?':
printf("unknown option: %c\n", optopt);
break;
}
}
// optind is for the extra arguments
// which are not parsed
for(; optind < argc; optind++){
printf("extra arguments: %s\n", argv[optind]);
}
return 0;
}
So, when you pass -f, you need to also pass filename, like: ./args -f filename it will say:
$ ./a.out -f file.txt
filename: file.txt
When you pass -i, -l, or -r, or -ilr, it will say:
$ ./a.out -ilr
option: i
option: l
option: r
If you pass -f but without a filename, it will say option needs argument. Anything else will be printed to extra arguments
So, with it, you can add options to getopts, add new case, do a thing, like:
getopts(argc, argv, ":fn:")
-f filename, -n number, pretty easy

Segmentation fault in atoi command

I have the following code:
int main(int argc, char *argv[])
{
int value,direction=0;
char c;
printf ("go\n");
while((c = getopt(argc, argv, "wr:")) != -1) {
printf ("go\n");
printf("%c\n",c);
switch(c) {
case 'w':
printf ("go\n");
value=atoi(optarg);
printf ("go\n");
printf("The input value is %x",value);
direction=1; //1 for write
break;
case 'r':
direction=0; // 0 for read
break;
default:
printf("invalid option: %c\n", (char)c);
usage();
return -1;
}
}
}
Now when i run the program by writing
./spicode.out -w 25
I need to pick the 25 after w using optarg, but its producing a segmentation fault.
What am i doing wrong?
You should put colon between commandline options.
c = getopt(argc, argv, "w:r")
From gnu.org :
An option character in this string can be followed by a colon (‘:’) to
indicate that it takes a required argument
Therefore wr: becomes w:r

getopt isn't working for one argument

This is just a simple program I wrote in order to get some practice with getopt, and structs.
typedef struct {
int age;
float body_fat;
} personal;
typedef struct {
const char *name;
personal specs;
} person;
int main(int argc, char *argv[])
{
char c;
person guy;
while((c = getopt(argc, argv, "n:a:b:")) != -1)
switch(c) {
case 'n':
guy.name = optarg;
break;
case 'a':
guy.specs.age = atoi(optarg);
break;
case 'b':
guy.specs.body_fat = atof(optarg);
break;
case '?':
if(optopt == 'a') {
printf("Missing age!\n");
} else if (optopt == 'b') {
printf("Missing body fat!\n");
} else if (optopt == 'n') {
printf("Missing name!\n");
} else {
printf("Incorrect arg!\n");
}
break;
default:
return 0;
}
printf("Name: %s\nAge: %i\nFat Percentage: %2.2f\n",
guy.name, guy.specs.age, guy.specs.body_fat);
return 0;
}
Everything works just fine except for the 'b' option. For some reason specifying that one doesn't change anything. It always returns as 0.0. I don't get why this would be if the other args work just fine.
Your example is missing the header files which would declare the corresponding prototypes. Adding these
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
makes it work for me. I also changed the type for c to int (a char will not hold a -1), and did a
memset(&guy, 0, sizeof(guy));
just to ensure it was a known value. Compiler warnings are your friend. I used this (a script named gcc-normal) to apply warnings:
#!/bin/sh
# $Id: gcc-normal,v 1.4 2014/03/01 12:44:54 tom Exp $
# these are my normal development-options
OPTS="-Wall -Wstrict-prototypes -Wmissing-prototypes -Wshadow -Wconversion"
${ACTUAL_GCC:-gcc} $OPTS "$#"
Though the RCS-identifier is fairly recent, it is an old script which I use in builds.

Using getopt with no arguments

By default I want the program will read input from stdin and send it's output to stdout.
The -f option will cause the
program to read the input from a text file and the -o option will cause the program to write the
output to a file instead of stdout.
The –c if specified will display the output in a CSV format (either in stdout or to a file depending if -o is specified).
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <ctype.h>
int main(int argc, char * argv[]){
char opt;
char *filename_in, *filename_out;
int i, flagC=0,flagF=0,flagO=0;
while((opt = getopt(argc,argv,"cf:o:")) != -1){
switch(opt){
case 'c':
flagC=1;
break;
case 'o':
flagO=1;
filename_out = optarg;
break;
case 'f':
flagF=1;
filename_in = optarg;
openFile(filename_in);
break;
case '?':
printf("Opt ?");
return 0;
default:
printf("Opt Default");
return 0;
}
}
if((flagC==0) && (flagO==0) && (flagF==0)){
// puts("Please enter a string:");
}
for (i = optind; i < argc; i++)
printf("%s ", argv[i]); //prints anything without argument and space between
return 0;
}
Is there a better way to read input from stdin aside from checking each flag I created is set to 0?
char input[100];
if((flagC==0) && (flagO==0) && (flagF==0)){
// puts("Please enter a string:");
// scanf("%s", &input);
}

Resources