What happens to command line arguments once printf() is used on them? - c

So I've written this small program, and I'm a newbie. It prints out the command line arguments I give it. I just don't understand why it worked before I changed the i variable to be initialized to one, yet when I changed it I get a segmentation fault.
The code:
#include<stdio.h>
int main ( int argc, char *argv[] )
{
if ( argc > 1) {
printf( "Filename: %s has %d arguments.", argv[0], argc );
} else {
printf ("No arguments found!");
getchar();
return 0;
}
int i = 1;
printf( "The arguments are: \n" );
for ( i < argc; ++i;) {
printf( "Argument %d is: %s \n", i, argv[i] );
}
getchar();
return 0;
}
I've never seen anything which says something happens to the command line arguments once they have been used. However my hypothesis is something happened to the command line arguments after I used printf() on them. It worked the first time when the counter variable i was initialized to zero. When I retooled the program to skip the zero-eth by initializing i to one the argument gave me that segmentation fault. I did this because I was a bit confused about what was happening. It wasn't printing out the filename a second time like I thought it would yet I changed it so it wouldn't anyway (makes a lot of sense huh? Not in retrospect lol).

Your for loop is broken:
for(;i<argc;++i)
The first block is the initial condition and the second block is the check performed before each iteration. As you wrote it, the check was ++i which would be true even after the last argument.

The correct way to use the for...next loop is like so (for C 1990/1989):
int i;
printf( "The arguments are: \n" );
for ( i = 0; i < argc; i++) {
Many people were complaining about my lack of knowledge about the syntax. I do know how to write a for...next loop. I've written many in C++ and C is almost no different. I followed the compilers warnings and adjusted but did not really think about what I was doing or check for anyone else with the same problem.
Because the compiler I am using GCC does not completely support C99 and I chose to stick with C90 as my compiling option. I am just learning C and I've found it a lot like C++ (fancy that) but I do not claim to know everything about C, or its previous versions.

if you're working with C you should first initialize declare and initialize i and do you if statement your program works fine if you change the placement of int i = 1

Related

Comparing char array elements

I'm trying to arrange this character array that only contains digits,it prints the same array with the order I input it without any change , i tried using type casting in the if statement, it gave me correct results when running but it wasn't accepted by the online judge.what is the fault here and why isn't my second solution accepted?
#include <stdio.h>
#include <string.h>
int main() {
char x[101];
scanf("%s",x);
int l,i,j ;
l = strlen(x);
char temp ;
for(i=0;x[i];i++)
{
for( j=i ; x[j] ; j++){
if('x[j]'<'x[i]') //(int)x[j] and (int)x[i] didn't work on the
//online judge
{
temp=x[i];
x[i]=x[j];
x[j]=temp;
}
}
}
printf("%s",x);
return 0 ;
}
I have no idea why there are quotes around the array elements, but that is not doing what you think, the comparison is happening because a multicharacter string is evaluated to an integer value which is implementation defined, hence the if statement is always comparing the same values, which means that it will always give the same result, you need to remove the quotes
if (x[j] < x[i])
Also, i'd recommend specifying the length of the array to scanf() and checking that it successfuly read the value, like this
if (scanf("%100s", x) != 1)
return -1; /* Perhaps EOF, i.e. you pressed Ctrl+D or (Ctrl+Z MS Windows) */
If you don't check your program will invoke undefined behavior, and if here it doesn't hurt any critical part of your simple program, if you don't learn to do it, then you will have a lot of hard do debug bugs in the future when you write a bigger program.
The quotes in your if statement evaluate to multicharacter constants, which in my compiler (VC++ 2013) happen to be 785B6A5D and 785B695D respectively, which are the ASCII codes of these characters glued together. Thus that if never executes. Also, what do you mean by "didn't work"? Did you get a compilation error? If yes, what did it say? Otherwise you may have exceeded the time limit since bubble sort is extremely slow.

How to check if the argument passed is a string in c?

I have the following code :
void test(int N)
{
printf("%d", N);
}
int main(int ac, char **av)
{
test("");
return 0;
}
I have a function test that expects an integer argument, but in the main when I call the function I give a string argument and c converts it to a integer and prints it for me. But what I want is that if someone passes a string than I give an error. How to check whether the argument is a string though ?
Thanks !
void test(int N) { /* ... */ }
...
test("");
That function call is simply invalid. test requires an argument of type int, or of something that's implicitly convertible to int (any arithmetic type will do). "" is a string literal; in this context, it's converted to a char* value which points to the '\0' character which is the first (and last, and only) character of the array.
There is no implicit conversion from char* to int. A conforming compiler must issue a diagnostic for the invalid call, and it may (and IMHO should) reject it outright. It's exactly as invalid as trying to take the square root of a string literal, or add 42 to a structure.
Older versions of C (before the 1989 ANSI standard) were more lax about this kind of thing, and that laxity survives into some modern compilers. It's likely that, if your compiler doesn't reject the call, it will take the address of the string literal and convert it to an int. The result of this conversion is largely meaningless; such a compiler really isn't doing you any favors by permitting it.
If your compiler doesn't reject, or at the very least warn about, the call, you should enable whatever options are necessary to make it do so. For gcc, for example, you might try something like:
gcc -std=c99 -pedantic -Wall -Wextra filename.c
You can drop the -pedantic if you want to use gcc-specific extensions. There are several possible arguments for the -std= option. See the gcc documentation for more information -- or the documentation for whatever compiler you're using.
If you're asking about validating user input (i.e., input from someone running your program rather than writing C code), user input is not generally in the form of numbers. It's in the form of text, sequences of characters. For example, you might use the fgets() function to read a line of text from standard input. You can then, if you like, check whether that line has the form of an integer literal. One way to do that is to use the sscanf function. A quick example:
#include <stdio.h>
int main(void) {
char line[200];
int n;
printf("Enter an integer: ");
fflush(stdout);
fgets(line, sizeof line, stdin);
if (sscanf(line, "%d", &n) == 1) {
printf("You entered %d (0x%x)\n", n, (unsigned)n);
}
else {
printf("You did not enter an integer\n");
}
}
But if your question is about someone writing C code that calls a function you provide, the compiler will check that any arguments are of a valid type.
what I want is that if someone passes a string than I give an error
That's not really your problem. Most compilers will give a warning for this, I think -- presuming warnings are enabled.
The issue is that C always passes by value, but a string argument is an array, and its value is the address of the first character in the array -- a pointer, but pointer values can be treated as integers. Again, most compilers are smart enough to catch this ambiguity, if you use them properly.
You can't completely bulletproof your code against people who use it improperly. You write an API, you document it, but you don't have to cover cases for those who cannot use basic tools properly.
The core standard C library does not include checks of the sort you are looking for here, so it seems pointless to incorporate them into your API -- there are oodles of built-in standard commands with int args to which an array can be passed in the same way. Saving someone from doing something stupid with your library won't save them from doing the exact same thing with the base C lib -- i.e., you can't stop them from passing pointers in place of ints. Period.
The naive approach is something like this:
int is_integer( const char *s )
{
if( *s == '-' || *s == '+' ) s++;
while( isdigit(*s) ) s++;
return *s == 0;
}
That will tell you if all characters are digits, with an optional sign. It's not particularly robust, however. It can't handle whitespace, and it doesn't check the integer is in the valid range.
However, it might be enough for your needs.
Example:
int main( int argc, char **argv )
{
int val;
if( argc <= 1 || !is_integer(argv[1]) ) {
fprintf( stderr, "Syntax: %s val\n\nWhere val is an integer\n", argv[0] );
return 1;
}
val = strtol( argv[1], NULL, 10 );
test(val);
return 0;
}
Compile with -Wall and -Werror and your problem will magically go away.
gcc -Wall -Werror file.c

C - Error while running .exe file that I compiled

I used geany to compile my code and no errors were found.
But when I run the .exe file the program stops working, and I'm not a good programmer, this is a work for school.
My program consists of reading 2 words, in this words its going to count how many letters each one has, and then he divides de number of letters in wordA for number of letters in wordB.
This is my code
#include <stdio.h>
int main(int argc, char *argv[])
{
int i, j;
float n;
printf ("Insert first word:\n");
for(i=0; argv[1][i] != '\0'; i++);
printf ("Insert second word:\n");
for(j=0; argv[2][j] != '\0'; j++);
n=i/j;
printf("%.4f", n);
return 0;
}
In this line
n = i/j;
you are performing integer division. So, for example, let's say that i is 3 and j is 5, then you perform 3/5 which equals 0.
But I think you are looking to perform 3.0/5.0 and hoping for the answer 0.6. So you need to perform floating point division. You can force that by casting one of the operands to a float.
n = (float)i/j;
In the question you wrote Int rather than int. I assumed that was a transcription error when asking the question. But perhaps your real code looks like that. In which case, you'll need to change it to int to get it to compile.
The other possible problem you have is that the program expects arguments to be passed on the command line. Are you passing two arguments to your program? In other words you need to execute your program like this:
program.exe firstword secondword
If you are not passing arguments then you will encounter runtime errors when attempting to access non-existent arguments in argv[]. At the very least you should add a check to the program to ensure that argc==3.
If you want to read the input from stdin, rather than passing command line arguments, use scanf.
I think this is a conceptual error. Your program (probably) runs fine when called like this:
myapp word1 word2
But I think you expect it to work like this:
myapp
Insert first word:
> word1
Insert second word:
> word2
But that's not what argv is about. You should look into scanf
Specifically, the error in the second case is because argv[1] is NULL, so argv[1][i] is a bad memory access.

Line counting and abberant results

I'm writing a utility to count the lines in a given file via the Unix command line. Normally this would be dead simple for me, but apparently I'm having a major off night. The goal of this program is to take in an unknown number of files from the command line, read them into a buffer and check for the newline character. Sounds simple?
int size= 4096;
int main(int argc, char *argv[]){
int fd, i, j, c, fileLines, totalLines;
char *buf= (char *)malloc(size); //read buffer
for (i=2; i<argc; i++){ //get first file
fileLines=1;
if ((fd=open(argv[i], O_RDONLY))!= -1){ //open, read, print file count, close
while ((c= read(fd, buf, size))!= 0){
for (j=0; j<size; j++){
if (buf[j] == '\n')
fileLines++;
}
}
}
printf("%s had %d lines of text\n", argv[i], fileLines);
totalLines+= fileLines;
close(fd);
}
printf("%d lines were counted overall\n", totalLines);
return 0;
}
I have two problems. The first is that the first printf statement is never executed outside of the debugger. The second thing is the totalLines printout should be roughly 175K lines, but the printed value is about 767 times larger.
I'm having trouble understanding this, because all the relevant variables have been declared out of scope from their modification, but that still doesn't explain why the first print statemeent and line counter update is ignored outside of the debugger along with the abberant totalLines result
Any help is appreciated.
ANSWER
Two changes were suggested.
The first was to change j<size to j<c. While this was not the solution required, it follows good coding convention
The second was to change i=2 to i=1. The reason I had the original start variable was the way I started the debugger executable. In the gdb command line, I entered in run lc1 f1.txt to start the debugger. This resulted in the arglist having three variables, and I didn't know that run f1.txt was perfectly suitable, since my professor introduced us to gdb by using the first example.
You're not initializing totalLines. You increment it inside of your loop, but you don't set it to 0 when you first declare it.
Also, why do you start from i=2? This is the third command-line argument, and the second parameter to your program. Is this what you intended, or did you want to start from the first parameter to your program?
And as others have pointed out, you should have j < c instead of j < size.
Your loop is wrong. It should be j=0; j<c; j++. That's probably not directly responsible for the errors you're seeing but will definitely cause problems.
Did you try stepping through the code with a debugger?
Consider: ./program file.txt
argv[0] is "program"
argv[1] is "file.txt"
which means your for loop starts from the wrong index, and if you are passing only 1 file through the cmd line your code will never enter in that loop! It should start at index 1:
for (i=1; i<argc; i++){
Do yourself a favor and initialize all variables when you declare them. Is the only way to ensure that there will be no garbage on those memory locations.
First, excellent question. :) All the necessary code, well stated, and it's obvious you've done your work. :)
How are you starting your program when in the debugger? I think the argv[2] starting point might be related to not reaching the printf(), but it would depend upon how you're starting. More details below.
A few comments:
int size= 4096;
Typically, C preprocessor macros are used for this kind of magic number. I know your teachers probably said to never use the preprocessor, but idiomatic C would read:
#define SIZE 4096
for (i=2; i<argc; i++){ //get first file
Try i=1 -- argv[0] is the name of the program, argv[1] is going to be the first command line argument -- presumably if someone calls it via ./wc foo you want to count the number of lines in the file foo. :) (Also, you want the loop to terminate. :) Of course, if you're trying to write a replacement for wc -l, then your loop is alright, but not very helpful if someone screws up the arguments. That can safely be kept as a project for later. (If you're curious now, read the getopt(3) manpage. :)
if ((fd=open(argv[i], O_RDONLY))!= -1){
while ((c= read(fd, buf, size))!= 0){
for (j=0; j<size; j++){
You are ending the loop at j<size -- but you only read in c characters in the last block. You're reading left-over garbage on the last block. (I wouldn't be surprised if there are generated files in /proc/ that might return short reads out of convenience for kernel programmers.)
if (buf[j] == '\n')
fileLines++;
}
}
}
printf("%s had %d lines of text\n", argv[i], fileLines);
totalLines+= fileLines;
This is the first time you've assigned to totalLines. :) It is liable to have garbage initial value.
close(fd);
You should probably move the close(fd); call into the if((fd=open())) block; if the open failed, this will call close(-1);. Not a big deal, but if you were checking the close(2) error return (always good practice), it'd return a needless error.
}
Hope this helps!
You're probably aware of wc, but I'll mention it just in case.
I know it doesn't directly help you debug your specific problem, but maybe you could glance at the source code and/or use it to verify that your program is working.
You have logical error in for() loop. You should use "bytes read" instead "read up to", what I mean in your code use "c" instead "size" in for()

Arguments to main in C [duplicate]

This question already has answers here:
Pass arguments into C program from command line
(6 answers)
Closed 6 years ago.
I don't know what to do! I have a great understanding of C basics. Structures, file IO, strings, etc. Everything but CLA. For some reason I cant grasp the concept. Any suggestions, help, or advice. PS I am a linux user
The signature of main is:
int main(int argc, char **argv);
argc refers to the number of command line arguments passed in, which includes the actual name of the program, as invoked by the user. argv contains the actual arguments, starting with index 1. Index 0 is the program name.
So, if you ran your program like this:
./program hello world
Then:
argc would be 3.
argv[0] would be "./program".
argv[1] would be "hello".
argv[2] would be "world".
Imagine it this way
*main() is also a function which is called by something else (like another FunctioN)
*the arguments to it is decided by the FunctioN
*the second argument is an array of strings
*the first argument is a number representing the number of strings
*do something with the strings
Maybe a example program woluld help.
int main(int argc,char *argv[])
{
printf("you entered in reverse order:\n");
while(argc--)
{
printf("%s\n",argv[argc]);
}
return 0;
}
it just prints everything you enter as args in reverse order but YOU should make new programs that do something more useful.
compile it (as say hello) run it from the terminal with the arguments like
./hello am i here
then try to modify it so that it tries to check if two strings are reverses of each other or not then you will need to check if argc parameter is exactly three if anything else print an error
if(argc!=3)/*3 because even the executables name string is on argc*/
{
printf("unexpected number of arguments\n");
return -1;
}
then check if argv[2] is the reverse of argv[1]
and print the result
./hello asdf fdsa
should output
they are exact reverses of each other
the best example is a file copy program try it it's like cp
cp file1 file2
cp is the first argument (argv[0] not argv[1]) and mostly you should ignore the first argument unless you need to reference or something
if you made the cp program you understood the main args really...
For parsing command line arguments on posix systems, the standard is to use the getopt() family of library routines to handle command line arguments.
A good reference is the GNU getopt manual
Siamore, I keep seeing everyone using the command line to compile programs. I use x11 terminal from ide via code::blocks, a gnu gcc compiler on my linux box. I have never compiled a program from command line. So Siamore, if I want the programs name to be cp, do I initialize argv[0]="cp"; Cp being a string literal. And anything going to stdout goes on the command line??? The example you gave me Siamore I understood! Even though the string you entered was a few words long, it was still only one arg. Because it was encased in double quotations. So arg[0], the prog name, is actually your string literal with a new line character?? So I understand why you use if(argc!=3) print error. Because the prog name = argv[0] and there are 2 more args after that, and anymore an error has occured. What other reason would I use that? I really think that my lack of understanding about how to compile from the command line or terminal is my reason for lack understanding in this area!! Siamore, you have helped me understand cla's much better! Still don't fully understand but I am not oblivious to the concept. I'm gonna learn to compile from the terminal then re-read what you wrote. I bet, then I will fully understand! With a little more help from you lol
<>
Code that I have not written myself, but from my book.
#include <stdio.h>
int main(int argc, char *argv[])
{
int i;
printf("The following arguments were passed to main(): ");
for(i=1; i<argc; i++) printf("%s ", argv[i]);
printf("\n");
return 0;
}
This is the output:
anthony#anthony:~\Documents/C_Programming/CLA$ ./CLA hey man
The follow arguments were passed to main(): hey man
anthony#anthony:~\Documents/C_Programming/CLA$ ./CLA hi how are you doing?
The follow arguments were passed to main(): hi how are you doing?
So argv is a table of string literals, and argc is the number of them. Now argv[0] is
the name of the program. So if I type ./CLA to run the program ./CLA is argv[0]. The above
program sets the command line to take an infinite amount of arguments. I can set them to
only take 3 or 4 if I wanted. Like one or your examples showed, Siamore... if(argc!=3) printf("Some error goes here");
Thank you Siamore, couldn't have done it without you! thanks to the rest of the post for their time and effort also!
PS in case there is a problem like this in the future...you never know lol the problem was because I was using the IDE
AKA Code::Blocks. If I were to run that program above it would print the path/directory of the program. Example: ~/Documents/C/CLA.c it has to be ran from the terminal and compiled using the command line. gcc -o CLA main.c and you must be in the directory of the file.
Main is just like any other function and argc and argv are just like any other function arguments, the difference is that main is called from C Runtime and it passes the argument to main, But C Runtime is defined in c library and you cannot modify it, So if we do execute program on shell or through some IDE, we need a mechanism to pass the argument to main function so that your main function can behave differently on the runtime depending on your parameters. The parameters are argc , which gives the number of arguments and argv which is pointer to array of pointers, which holds the value as strings, this way you can pass any number of arguments without restricting it, it's the other way of implementing var args.
Had made just a small change to #anthony code so we can get nicely formatted output with argument numbers and values. Somehow easier to read on output when you have multiple arguments:
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("The following arguments were passed to main():\n");
printf("argnum \t value \n");
for (int i = 0; i<argc; i++) printf("%d \t %s \n", i, argv[i]);
printf("\n");
return 0;
}
And output is similar to:
The following arguments were passed to main():
0 D:\Projects\test\vcpp\bcppcomp1\Debug\bcppcomp.exe
1 -P
2 TestHostAttoshiba
3 _http._tcp
4 local
5 80
6 MyNewArgument
7 200.124.211.235
8 type=NewHost
9 test=yes
10 result=output

Resources