Why does this subnetting class app freeze up? - c++

This code is C/C++ and runs without warnings or debug messages. I'm using Code::blocks with the GNU GCC compiler. This app worked perfectly once, then somewhere along the lines I messed up without noticing. Now every time it will allow a ip address input, but then freeze up and close. Why?
#include <iostream>
#include <string>
#include <cstdio>
using namespace std;
int ip[3];
char * inputIP;
int x;
string classValue;
void subnetClass()
{
if (x==0) classValue="Error: first octet may not be zero.";
if (x>0 && x<=126) classValue="Class A";
if (x==127) classValue="Loopback Address";
if (x>=128 && x<=191) classValue="Class B";
if (x>=192 && x<=223) classValue="Class C";
if (x>=224 && x<=239) classValue="Class D";
if (x>=240 && x<=255) classValue="Class E";
if (x>255) classValue="Error: an octet may not be more than 255.";
cout << classValue << endl;
}
int main()
{
cout << "Enter IP address in dotted-decimal form." << endl;
cin >> inputIP;
scanf(inputIP, "%d.%d.%d.%d" , &ip[0],&ip[1],&ip[2],&ip[3]);
int x=ip[0];
subnetClass();
return 0;
}
Build Log:
Checking for existence: C:...\IP subnetting app\bin\Debug\IP subnetting app.exe
Executing: "C:...\CodeBlocks/cb_console_runner.exe" "C:...\IP subnetting app\bin\Debug\IP subnetting app.exe" (in C:...\IP subnetting app.)
Process terminated with status -1073741510 (0 minutes, 27 seconds)

You are declaring a variable 'x' that is hiding the global one.
int x=ip[0];
However, don't do it this way. Add an int parameter to subnetClass and pass in the value that way, and remove the global variable.
Really, removing all of your globals should be a goal and easy to accomplish. Several are only used in main().

It might have worked with a little help from sheer luck even if you messed things up later, I believe. More or less everything is wrong. First you read the line into the area pointed to by uninitialized pointer (or maybe you read the pointer value, I'm not even sure what >> (char*) is supposed to do). You better change the definition to
std::string inputIP;
then you try to parse it used scanf and pass this pointer as a format string. What you meant is using sscanf. Assuming you changed the inputIP type, you can use
sscanf(inputIP.c_str(),"%d....
Then you assign to local main variable x that shadows global, which remains uninitialized when you use it in the function. Just remove the int part in the assignment like this:
x=ip[0];
and make the ip array of four elements.
int ip[4];
Then it may work. Unless I missed something else.
And one more thing: if you use some source control (for instance using git you may start new project in no time) then you'd know what you've changed when you mess up, just commit early, commit often.

Use sscanf instead of scanf

Related

Is it possible to input an address to a pointer from stdin?

Not that long ago, I had an idea for some simple inter-process comunication: one process outputs an address to a pointer, I copy that to the input of another process, and that changes the original variable.
I implemented it like this:
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
bool p;
cin>>p;
if(p){
int n;
n=0;
cout<<&n;
cin.get();
cin.get();
cout<<n;
}else{
int *point,n;
scanf("%p",&point);
cout<<point;
cin>>n;
*point+=n;
}
return 0;
}
I used scanf because cin complained, and wouldn't compile. I tried to run it, with two processes, but after I launched the second instance, and input the pointer's address, as outputed by the first, it froze. As I only have access to Windows, I have no idea as to whether it got a SIGSEGV, or if it did something completely diferent.
Is it just me trying to change the value of another process's variable that is crashing it, or is it something else that is stopping me?
You cannot do this that way because first process will not have access to the second process' memory address space (in common operating systems, including Windows and Linux).
Each process has its own memory, completely separate from that of other processes. A pointer value is meaningless in context of a different process, even if you manage to get it across.

Using 'assert' to verify number of arguments

I was working on an assignment for class, and I think I got the program working properly, but now I would like to make some modifications to it just to better understand assert. The code is below -
#include <iostream>
#include <stdlib.h>
#include <assert.h>
using namespace std;
// Sample program that shows how command line arg works, in Unix g++
// Note argc and argv
// Also shows use of system call, that can launch any program
// system launches 'ls' to display files in the dir
void runAssert(int);
int main(int argc, char *argv[])
{
cout << "Number of inputs: " << argc << endl;
cout << "1st argument: " << argv[0] << endl;
system ("ls");
cout << "hello world" << endl;
runAssert(argc);
return 0;
}
void runAssert(int argc)
{
assert(argc > 4);
}
So the program is supposed to keep track of the arguments passed into main through command line. The professor specified that it should take 4 arguments. This code works, as far as I can tell, but I don't know what 4 commands to pass it? I do g++ assignment.cpp -o assignment
and then ./assignment -- But this last command only counts as one argument so the assert triggers. If I change the function to >= 1 then it works.
Another question I have is, how can I make it display an error message when it doesn't meet the requirements?
I have tried assert("Not the right amount of arguments", argc > 4) but then I get an error message about too many arguments being passed into main.
Thanks for any help, and sorry if my formatting is wrong. First time posting.
This is a completely incorrect usage of assert. Use assert to state things that you, as a programmer, think are logically necessary. It is logically possible for someone to call your program with fewer than 4 arguments, so assert is not correct.
A common usage of assert is at the start of a function. (This is not validating arguments.) Consider int foo(void *k){ assert(k != NULL); ...} Once again, this is not validating the argument k. The assertion is a piece of documentation that tells the human writing the code at the call site that foo is not to be called with a NULL argument. It is a claim that in the properly written code, it is a logical necessity that k be non-null. If you want to validate the argument and generate a pretty error message, use an if statement.
One thing about assert is that you should assume it does not execute in normal operation. Typically, the program will be compiled with -DNDEBUG, which will turn all of the assertions into whitespace.
ok the number of arguments should be checked before you start executing any of the program code.
In this case i guess the professor wanted you to pass the arguments passed to the program to ls .so it should be something like
./assignment -l -s -a
In the above case the -l -s and -a are the arguments.
You can use an if condition to check the number of arguments instead of assert.
if (argc < 4) {
// print the error message
// exit from program
}
Check answer by william to know the reason why not to use assert in this case
I don't know what 4 commands to pass
That's up to you. You could do:
./assignment a b c d
You will get get argv[1]="a", argv[2]="b", etc.
Parsing and using these arguments is up to you; in this context you could try to find an example of processing the arguments. Maybe print them in reverse order or something basic like that ?
Regarding assert(): your usage is not strictly correct as pointed out in another answer.
To answer your question, one simple way to display a message is by using && : https://stackoverflow.com/a/3692961/2750093
I don't think your professor would like that though, so you could do something a little bit more naive :
if (argc <= 4 )
{
printf("Not the right amount of arguments\n");
assert(false); // or return -1;
}
assert(condition) crashes the program with an error message like file bar.cc line 123: assertion failure 'condition'. As such it is not useful for the user, but it is useful for the developer.
Use assert to express expectations (on the state of certain internally controlled variables) that are assumed to hold in the code immediately following the assertion. Don't use assert to check user input (externally controlled variables), but throw an exception instead. Exceptions can be caught by the user, assertions cannot.

Why this behavior when declaring pointers in C++ using Unix and Windows systems?

I didn't found this question in Stack Overflow or Google, so sorry if it's a duplicate.
As I know, variables in C/C++ are not initialized. But recently a strange situation occur to me when using pointers. See the code below:
#include <iostream>
using namespace std;
struct Test {
int i;
};
struct Box{
Test *var;
};
int main() {
Box *t = new Box;
cout << t->var;
}
In Windows, the output I get is something like (what is expected):
0x3e0178
But, in Unix systems, the output is:
0x0
Why this happen? Does the compiler initialize the pointers in a recursive way when new is invoked in Unix systems?
Also, with common variables the same happens. For the code below, the results are 0 in Unix systems and 4385838 in Windows:
int main() {
int i;
cout << i << endl;
}
UPDATE
In another test, the behavior this time was the same in both systems: the pointer p points to a random address in the memory.
int main() {
int *p;
cout << p;
}
Just to explain my question: I know we have to initialize the variables before using it, but a student was asking me why his program works fine in Unix systems and not in Windows. I found this pointer issue in his program, and I want to give a feedback.
In all modern (multiuser) operating systems, memory received directly form the os is zeroed, in order to avoid information leakage. What happens, is probably the Unix systems, because far less startup code must be run to set up a proper C runtime environment, main() by dumb luck got virgin memory, not reusing stack space previously used for a different function, to store i. The other possible explanation is, someone just stored a 0 there before.
Anyway, don't rely on it for heavens sake.

Very basic C++ program issue - Invalid operands to binary expression

I just started teaching myself C++ on the Mac, and I have run into some issues.
I have written some code that allows the user to enter a number and when they hit enter, the number will be returned to the user.
Xcode will absolutely not have it though. Every time I try to run my code, it says that there is an issue with the cin>> thisisanumber; code.
The error comes up and says
Invalid operands to binary expression. Error is on line 10.
What am I doing wrong?
#include <iostream>
using namespace std;
int main()
{
int thisisanumber();
cout << "Please enter a number: ";
cin >> thisisanumber;
cin.ignore();
cout << "You entered"<< thisisanumber <<"\n";
cin.get();
}
You've fallen victim to the most vexing parse, which means thisisanumber is being treated as a function. Take out the parentheses and you should be fine:
int thisisanumber;
Also consider making it a bit more readable, such as thisIsANumber. If you ever need to know it, thisIsANumber uses the camel-case naming convention.
Declare your variable without brackets, like
int thisisanumber;
With brackets, it is interpreted as a function, and a function can't be passed as a parameter to the >> operator.
Your problem is the so called most vexing parse. Basically everything, which could be parsed as a function declaration will be parsed as such. Therefore the compiler will interpret int thisisanumber(); as a declaration of a function thisisanumber taking zero arguments and returning an int. If you consider this behaviour the problems with cin>>thisisanumber; should be somewhat selfevident.
If you remove the parantheses, changing the variable declaration to int thisisanumber;, your program should behave like you'd expect it to with thisisanumber being a variable of type int.
You might however reconsider your naming conventions, thisisanumber isn't exactly readable. I would suggest going with this_is_a_number, thisIsANumber or ThisIsANumber.
int thisIsANumber;
try making it variable declaration because what you wrote has been interpreted as function.
delete () after thisisanumber, because () after thisisanumber means that it's a function, when it's not.

Segfault in atoi(str)

I'm new to the C/C++ game so I assume I'm making a rookie mistake:
int main(){
char* clen;
clen = getenv("CONTENT_LENGTH");
if (clen==NULL){
cout << "No such ENV var: CONTENT_LENGTH"<<endl;
exit(0);
}
int cl = 0;
cl = atoi(clen);
if (cl < 1){
return inputPage();
}
// if there is no content, we assume that this is a fresh request,
// so we showed the input page, otherwise, we'll return dispatch to
//the processing code.
postTest(clen);
}
This is supposed to be a CGI script. As far as I can tell with GDB, print statements, etc. this code segfaults on the line "cl = atoi(clen);" I have no idea why this is. K&R suggests that this is correct. I basically copied this line from a half dozen other online tutorials. And it seemed to be working last night! I'm totally stumped.
I don't believe that it really crashes on atoi()
Could you please try out this code?
#include <iostream>
#include <stdlib.h>
#ifndef NULL
#define NULL 0
#endif
using namespace std;
int main(){
char* clen;
clen = getenv("CONTENT_LENGTH");
if (clen==NULL){
cout << "No such ENV var: CONTENT_LENGTH"<<endl;
exit(0);
}
int cl = 0;
cl = atoi(clen);
if (cl < 1){
std::cout << "return inputPage();" << std::endl;
return 0;
}
std::cout << "postTest();" << std::endl;
}
compile it e.g. to "app" and run it with some variations of CONTENT_LENGTH, e.g.
./app
CONTENT_LENGTH=4 ./app
CONTENT_LENGTH=-4 ./app
CONTENT_LENGTH=a ./app
Barring compiler bugs and a bugged getenv() implementation I would say that it's impossible for that code to segfault on cl = atoi(clen). This is because getenv() returns either NULL or a valid pointer to a null terminated character array (that's just a fancy way to say C string).
Since the NULL case is checked against, most likely the program (it's not a "script") crashes somewhere else.
EDIT: How do you know it even crashes? Does it display an HTTP 500 error? If yes most likely you simply forgot cout << "Content-type: text/html\n\n". What do the web server logs say?
EDIT2: unrelated to your problem, but usually using C functions like atoi() is frowned upon; the C++ version lexical_cast (implemented in TR1 and boost) is preferred.
You write you've been looking at it with GDB. Shouldn't it be possible to just dig (step) into the atoi() function call to get a better idea of what's going on? I assume you made sure it never reaches the line past the atoi() call?
It turns out that this was not in any way an issue with atoi, or with C++ in general. The problem was that I had forgotten a very basic CGI point, which is that there is no CONTENT_LENGTH in a GET, which is what the first call from the browser inevitably is. Thus, I was trying to fiddle with the clen which was null. I simply needed to return the inputPage as soon as I discovered that there was no CONTENT_LENGTH attribute.