I thought to check if I know the basic things that are needed to write programs in C++.
Just ask me if I know what something is. I want to find the holes in my knowledge.
Printable View
I thought to check if I know the basic things that are needed to write programs in C++.
Just ask me if I know what something is. I want to find the holes in my knowledge.
Why is gets() not recommended?
Because it may cause buffer overflow.
Warning! I may not know much about C functions because I'm using C++.
why is using namespace std; appropriate?
It automatically detects std functions, structures and stuff without adding "std::" in front of them when you're using "using namespace std". You can "use" any namespace with that syntax (using namespace foo). This is totally useless if you don't use any of these functions.
nice
Now I will be inactive for 15 hours, it's almost midnight here.
One thing to add to this: you can import only one member of a namespace like so:Quote:
It automatically detects std functions, structures and stuff without adding "std::" in front of them when you're using "using namespace std". You can "use" any namespace with that syntax (using namespace foo). This is totally useless if you don't use any of these functions.
Code:using std::cout;
- (C question) What's wrong with fflush(stdin)?
- How do you keep a Windows console open?
- If you have only cin.get() at the end of your program to keep the console open, why might it not work?
- (C question) What header file is tolower() in?
- How do you overload the = operator and what are some pitfalls you must avoid when doing so?
- How do you use template specialization?
- Last one . . . what's a "function signature"?
If you want C++ questions to answer, either hang around on this board for a while or get a book. Most books have excersises in them.
You're disturbing my sleep :D . Good night everyone.
So much for inactive.
What is the correct type to use for a variable that can have two discreet values, neither of which has anything to do with the logical concept of truth?
Apart from verbosity, what is the difference between the two expressions 8192 and 8192 * sizeof(char)?
I'd say the real reason that the "using" keyword exists is for porting pre-1998 code onto standard compilers. There was 15 years worth of C++ code that existed before the standard, and making all of that code require hundreds of changes to compile would be unacceptable.Quote:
Originally Posted by maxorator
I assert that porting legacy code is the only valid reason for having "using" in your code. It decreases readability; putting std:: in front of everything makes it far more clear what's going on.
Anyhow, list every potential problem with the following code, and rewrite the function to get rid of all the problems you've identified. Your code should follow good C++ coding practices.
The code will compile and it does produce the output you expect, so there's no trick question here.Code:
void SomeFunction(char * str){
char * buffer = new char[256];
char * buffer2 = new char[256];
sprintf(buffer, "The contents of str are: %s",str);
sprintf(buffer2, "Skipping the first 10 characters of str gives: %s", str + 10);
std::cout << buffer << std::endl << buffer2 << std::endl;
delete[] buffer;
delete[] buffer2;
}
Sorry, just couldn't resist seeing that ;) Here's a code fix:
And here's an algorithm fix:Code:ibvq FbzrShapgvba(pune * fge)
{
pune *ohssre, *ohssre2;
gel
{
ohssre = arj pune[256];
}
pngpu(fgq::onq_nyybp)
{
fgq::pbhg << "Reebe!\a";
erghea;
}
gel
{
ohssre2 = arj pune[256];
}
pngpu(fgq::onq_nyybp)
{
fgq::pbhg << "Reebe!\a";
erghea;
}
fcevags(ohssre, "Gur pbagragf bs fge ner: %.230f", fge);
vs(fgeyra(fge) >= 10)
{
fcevags(ohssre2, "Fxvccvat gur svefg 10 punenpgref bs fge tvirf: %f", fge + 10);
}
ryfr
{
fcevags(ohssre2, "fge unf yrff guna 10 punenpgref");
}
fgq::pbhg << ohssre << fgq::raqy << ohssre2 << fgq::raqy;
qryrgr [] ohssre;
qryrgr [] ohssre2;
}
Solution #1 seems rather hackish, though.Code:ibvq FbzrShapgvba(pune * fge)
{
fgq::pbhg << "Gur pbagragf bs fge ner: " << fge << fgq::raqy
<< "Fxvccvat gur svefg 10 punenpgref bs fge tvirf: ";
sbe(fvmr_g v = 10, yra = fgeyra(fge); v < yra; ++v)
{
fgq::pbhg << fge[v];
}
fgq::pbhg << fgq::raqy;
}
I usually do put std:: in front of the functions that need it and I don't use the "using namespace std;".Quote:
I assert that porting legacy code is the only valid reason for having "using" in your code. It decreases readability; putting std:: in front of everything makes it far more clear what's going on.
dwks,
1. The behaviour of stdin with fflush is not defined in all compilers and it's not by the standard (I didn't know this before, I am quite stupid when it comes to C functions)
2.Cin.ignore() is a good solution, but when I am really in a hurry and the code IS STRICTLY only for my use, I just quickly add system("pause"); into the end, which is not very good solution actually.
3. If there are some previous functions used to read from the input stream (cin.get,cin.getline()), then the data that was not read (cin.get() reads only one,cin.getline() reads the number of characters you specify) is automatically passed to the next cin.get() or cin.getline() so the cin.get() function just got the character it needed and returns.Code:std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
4. In C, it is in the <string.h> library.
5. Checking for self-assignment? I haven't used = operator overloading...
6. Do you mean kind of overload the template with a template function that has parameters types specified, so when those types are used in the function, that function template is used?
7. It is some kind of information about the function (parameters, function name, scope and more).
CornedBee, could you just stop it? I don't need to argue with you.
zx-1, the second one works with 16bit, 32bit and 64bit Unicode versions too.
Thanks to dwks I got some "knowledge holes" filled.
Nope. That'd be with sizeof(wchar_t), assuming there's a difference between wide and and narrow chars.Quote:
Originally Posted by maxorator
I see no differences then because sizeof(char) is always 1 byte.
Actually it was midnight. I just thought I'd look if there's something interesting here before I went to sleep.Quote:
Originally Posted by Queatrix
That's 95% correct. There is a difference, albeit a somewhat esoteric one.Quote:
Originally Posted by maxorator
It was really kind of a trick question. :-)
Hmm, you can define char to be something else?
No. Answer:
8192 is the same as (int)8192.
8192 * sizeof(char) is the same as (size_t)8192.
I think that this is another valid use of "using":Quote:
I assert that porting legacy code is the only valid reason for having "using" in your code. It decreases readability; putting std:: in front of everything makes it far more clear what's going on.
At the initial point when the code was written, it is possible that the types of member1 and member2 do not yet have their own (presumably optimised) swap functions. As such, the standard swap algorithm would be used. At some later point, this might change, and thus a re-compile should have ClassName::swap pick up the optimisations automatically.Code:void ClassName::swap(ClassName& x) {
using std::swap;
swap(member1, x.member1);
swap(member2, x.member2);
}
Here is another valid use of "using":
If the "using Base::memberFunction;" was commented out, there would be a compile error, since Derived::memberFunction(int) hides the name "memberFunction" in the Base class' scope. As such, a call to Base::memberFunction() from x would be invalid.Code:#include <iostream>
class Base {
public:
void memberFunction() {
std::cout << "Base::memberFunction()" << std::endl;
}
virtual void memberFunction(int num) {
std::cout << "Base::memberFunction(" << num << ")" << std::endl;
}
};
class Derived : public Base {
public:
using Base::memberFunction;
virtual void memberFunction(int num) {
std::cout << "Derived::memberFunction(" << num << ")" << std::endl;
}
};
int main() {
Derived x;
x.memberFunction();
}
I think Cat was referring to the using statement, not the using declaration. But far be it from me to place words in his mouth ;)
zx-1: it actually took me two looks on your code to find the difference. Very nice example.
maxorator: no, but you need to learn good design.
Well, I see the difference too, one of them is shorter than the other one.
Look again. :)Quote:
4. In C, it is in the <string.h> library.
I mean that you can have a generic template class, like vector<>, but also a specialized version, such as vector<bool>, which has a slightly different behaviour.Quote:
6. Do you mean kind of overload the template with a template function that has parameters types specified, so when those types are used in the function, that function template is used?
What should you do if you detect an error while in a constructor? What about a destructor? Why is auto_ptr<> not appropriate for holding pointers that will be stored in standard containers? What is a good alternative? What is the airspeed velocity of an unladen swallow? Is that airspeed sufficient to carry a coconut?
Oh, sorry, accidentally compiled it as C++, stdio.h of course.Quote:
Look again.
The question: What header file is tolower() in?
Wrong! Better start using your grepping power.Quote:
Originally Posted by maxorator
Third time lucky.
Or man tolower or google("site:cppreference.com tolower") or countless other ways.Quote:
Better start using your grepping power.
What's the difference? Stdio.h automatically includes ctype.h.
What do you mean by "man"?
Where does it say that?Quote:
Originally Posted by maxorator
The Unix man pages.Quote:
What do you mean by "man"?
I can use tolower() when I only include <stdio.h>.Quote:
Originally Posted by CornedBee
I don't use UNIX so I don't know about it's man pages.
On every compiler that exists? Every compiler that might be written?Quote:
Originally Posted by maxorator
The standard is what counts.
So you are saying that <stdio.h> is not a standard header?
No. He's saying that you got it wrong twice. tolower() is defined in <ctype> whether you like it or not. If your compiler implementation has <ctype> included in <stdio.h>, fine. Other implementations may not.
You mean <ctype.h>, right? :)
On UNIX (or Linux, or Cygwin -- an implementation of bash for Windows), you can generally typeQuote:
I don't use UNIX so I don't know about it's man pages.
and get information about that function. There are man pages for programs, functions, system calls, etc, divided into 7 sections by type. (For example, printf() has two man pages, for the program and for the function. To access the man page for the function, type man 3 printf.)Code:$ man function
> You mean <ctype.h>, right?
Yeah. an oversight. Or <cctype> and <cstdio> for all that matters. The point tough being that an implementation is free to decide on how it integrates the several headers. On my implementation #include <iterator> is all I need to use std::string. But that doesn't make it right.
Well you never answered the first question I posed to you (I'll post an answer soon) but here's another one anyway:
What is the difference (in functionality) between a, b, and c?Code:const char * a;
char const * b;
char * const c;
I can honestly say that I don't know...
Well on the first you create a pointer to a const char. You promise you will not alter the value of a. It is also the only way to create a pointer with the address of a const object.
The second is the same as the first. It's using one of the shady syntaxes of C++; the const qualifier after the type.
On the third you create a const pointer to char. You promise you are not going to alter the pointer itself. That is you cannot make it point to something else other than what it was initialized with.
When you come across situations like this, just remember to read them backwards.Quote:
Originally Posted by maxorator
const char * a;
"a is a pointer to a character that is constant"
char const * b;
"b is a pointer to a constant character"
char * const c;
"c is a constant pointer to a character"
These have to do with:
* Whether or not you can change the address the pointer contains (i.e. where the pointer is pointing), and
* Whether or not you can change the contents of the memory the pointer is pointing at.
a and b are identical, with a being the "normal" syntax and b being an alternative; the pointer is not constant (so you could modify the pointer to point to a new area of memory) but the character(s) that it points to ARE constant. For example:
a = &x; // This is legal, because you change where a points to (the address that a holds)
*a = 'A'; // This is illegal because you may not change the contents of the character/string it points to.
c is the opposite -- you cannot change the address that c holds (the pointer is constant) but you CAN modify the memory at that address:
c = &x; // Illegal, you're trying to change the address that c holds.
c[10] = 'C'; // Legal, you can use c to modify the memory it points to.
You can also do one other kind of pointer:
const char * const d;
"d is a constant pointer to a character that is constant"
In that case, you may not alter the pointer OR the memory it points to.
What's wrong with this?
Code:const char **x;
Tricky. :) Took me a awhile. But I didn't cheat.
A char** is not actually a pointer to pointer to char. But instead an array of pointers to char. (as we know from one of the main signatures; main(int argc, char **argv)). Being const means the definition needs to be initialized. Const objectsneed to be initialized at the point of declaration. In your example it wasn't.
A char** is absolutely a pointer to pointer to char. That pointer to a pointer to a char can be pointing at an array of pointers to char, but there is nothing that says it has to.
Also, I think that x can be initialized later, so your second point is wrong as well.
I don't know the exact details, but you can't have a const pointer to a pointer. Perhaps someone can explain why.
constants must be initialized. Your compiler will agree.
Owner@pavilion ~Code:$ cat const.cc
int main()
{
const char **x;
**x = '!'; // dammit
}
$ g++ const.cc
const.cc: In function `int main()':
const.cc:4: error: assignment of read-only location
A const pointer to a pointer would be:Quote:
Originally Posted by dwks
char ** const x;
Remember the rule with pointers is to read them backwards: "x is a const pointer to a pointer to a char"
And that does work for me, this code compiles:
char * y;
char ** const x = &y;
In fact all variations compile for me:
const char ** a; (a pointer to a pointer to a const char)
char * const * b; (a pointer to a const pointer to a char)
char **const c; (a const pointer to a pointer to a char)
const char * const * const d; (a const pointer to a const pointer to a const char)
But yes, if the pointer is const (as in c and d above), it needs initialization just like any const variable:
I think what you were thinking of was the following, and one of the ways that a constant pointer and a reference are different:Code:const char x = 'x';
const char * const y= &x;
const char * const * const z = &y;
char * const * i; // Legal: pointer to const pointer.
char & * j; // Illegal: pointer to reference
No. It can't be initialized later.You try it. Your point is wrong.Quote:
Originally Posted by Daved
EDIT: Nope. I'm wrong. The pointer is not a constant.
My reply is pokey as all hell, but...
Code:#include <iostream>
using std::cout;
int main(void)
{
const char a = '5', c = '*';
const char *b, *d;
const char **x;
b = &a;
x = &b;
cout << "&a = " << static_cast<const void*>(&a) << ", "
<< "&b = " << static_cast<const void*>(&b) << ", "
<< "&c = " << static_cast<const void*>(&c) << ", "
<< "&d = " << static_cast<const void*>(&d) << "\n";
cout << "x = " << static_cast<const void*>( x) << ", "
<< "*x = " << static_cast<const void*>(*x) << ", "
<< "**x = '" << **x << "'\n";
b = &c;
cout << "x = " << static_cast<const void*>( x) << ", "
<< "*x = " << static_cast<const void*>(*x) << ", "
<< "**x = '" << **x << "'\n";
d = &a;
x = &d;
cout << "x = " << static_cast<const void*>( x) << ", "
<< "*x = " << static_cast<const void*>(*x) << ", "
<< "**x = '" << **x << "'\n";
d = &c;
cout << "x = " << static_cast<const void*>( x) << ", "
<< "*x = " << static_cast<const void*>(*x) << ", "
<< "**x = '" << **x << "'\n";
return 0;
}
/* my output
&a = 0022FF77, &b = 0022FF70, &c = 0022FF76, &d = 0022FF6C
x = 0022FF70, *x = 0022FF77, **x = '5'
x = 0022FF70, *x = 0022FF76, **x = '*'
x = 0022FF6C, *x = 0022FF77, **x = '5'
x = 0022FF6C, *x = 0022FF76, **x = '*'
*/
By the way, here is my solution for the previous problem:
First, in general this code suffers from what I call "C++--" -- it's basically C code that masquerades as C++. In fact changing that will solve every problem the code has, but first, the specific things that are wrong:Code:01 void SomeFunction(char * str){
02
03 char * buffer = new char[256];
04 char * buffer2 = new char[256];
05
06 sprintf(buffer, "The contents of str are: %s",str);
07 sprintf(buffer2, "Skipping the first 10 characters of str gives: %s", str + 10);
08
09 std::cout << buffer << std::endl << buffer2 << std::endl;
10
11 delete[] buffer;
12 delete[] buffer2;
13 }
Line 1: The parameter is not const-correct; the string is not modified and so it should be const char *.
Line 4: The new[] can throw an exception. It could on line 3 as well, but actually that doesn't cause a problem. If line 4 throws, the memory allocated successfully on line 3 cannot be deallocated, it's leaked.
Line 6: This assumes that the total length of the resulting string is less than 256 characters including a trailing NULL. If not: buffer overflow.
Line 7: This assumes not only the total length of the resulting string is less than 256 chars, but also that the source string is at least 10 characters long.
Line 9: If the iostream throws an exception when writing to console, both buffer and buffer2 are memory leaks, because memory that was successfully allocated will not be able to be deallocated as the pointers to that memory will be lost.
Here's a better source code:
In this, I could have made the parameter just a normal std::string (which, because it would be passed by copy, would not need to be const), but I chose reference to const as it will avoid constructing a copy if we pass in a std::string variable.Code:void SomeFunction(const std::string & str){
std::string buffer, buffer2;
buffer = "The contents of str are: " + str;
if (str.length() >= 10)
buffer2 = "Skipping the first 10 characters of str gives: " + str.substr(10);
else
buffer2 = "The string is less than 10 characters long";
std::cout << buffer << std::endl << buffer2 << std::endl;
}
If we pass in a string literal, it will construct a temporary std::string (which it would NOT do if the reference was not to const). This does take a slight time, but in reality it's virtually identical to the time needed to strlen() a const char * string, so there's no real problem using it.
Making the buffers string variables instead of character arrays eliminates any worry about overflow we had in the first, and also there's no chance of memory leak, even if one of the strings throws an exception; stack unwinding will deallocate all memory.
Declaring variables at the start of a function is another "C++--" bit of coding. Because we have something with which to initialize buffer, and because buffer2 isn't needed until later in the function, I might do somethig like this:Another possibility would be to construct buffer with ("The contents of str are: " + str); which may or may not be more clear or efficient or both. Also, I'd consider using '\n' instead of endl, although I'm not sure if operator<< can throw in between the outputs making the explicit flush actually necessary.Code:void SomeFunction(const std::string & str){
std::string buffer("The contents of str are: ");
buffer += str;
std::string buffer2;
if (str.length() >= 10)
buffer2 = "Skipping the first 10 characters of str gives: " + str.substr(10);
else
buffer2 = "The string is less than 10 characters long";
std::cout << buffer << std::endl << buffer2 << std::endl;
}
It can, if you have enabled exceptions for the iostream object. And if the underlying stream buffer throws. Thing is, if it throws an exception, do you really still care about the first output?Quote:
Originally Posted by Daved
I agree. In this case you can't tell whether the original coder did that on purpose or not, and since either choice is valid I wouldn't consider that something that is "wrong" with the original code.
Actually, that's a good point. That's an additional possible way that buffer[] and buffer2[] could be leaked in the original code. I edited my analysis to include that.Quote:
Originally Posted by CornedBee