I was wondering whether there is a way in C++ that a "string" (in whatever representation) that get's passed into a function can be assumed to be a valid string by that function.
I'm very new to C/C++ but so far as I can see, in C that question is answered by default because there is no other way und you just know that you have to check:
#include <stdio.h>
void foo(const char *str)
{
if (str)
printf("%s\n", str);
}
int main()
{
char *name = "Jack";
foo(name);
return 0;
}
But since C++ offers additional stuff like references I was wondering whether one could write foo() in such a way that it doesn't have to check. I tried it like this:
#include <iostream>
#include <string>
void foo(const std::string &str)
{
std::cout << str << std::endl;
}
int main(void)
{
std::string name = "Jack";
foo(name);
std::string *str = NULL;
foo(*str);
return 0;
}
But as you can see I can fool foo() to run into a SegFault. So, I guess you just always have to check, no matter what?
EDIT #1:
Okay, first of all thanks for all your answers and future answers, they are all much appreciated!
So to sum up what I learned so far:
There is no syntactic way in C++ to write a function defintion to
eliminate misuse by the actual function call.
Is that correct? If so, I see my original question as answered.
So now I trying to write foo() as defensive as possible, so that no matter how much you treat foo() like a dog, it just won't produce a SegFault.
In C I would now write it like this (assuming short-circut evaluation):
#include <stdio.h>
void foo(const char *str, const size_t len)
{
if (str && (str[len - 1] == '\0'))
printf("%s\n", str);
}
int main()
{
char *name = "Jack";
foo(name, 5);
/* possible mistakes, but foo can handle them */
foo(name, 4);
foo(name, -1);
foo(NULL, 5);
return 0;
}
And in C++ I'm trying this:
#include <iostream>
#include <string>
void foo(const std::string &str)
{
if (&str)
std::cout << str << std::endl;
}
int main(void)
{
std::string name = "Jack";
foo(name);
std::string *str = NULL;
foo(*str);
return 0;
}
...but I'm not sure if that is in any approriate or what one would, could or should do with exceptions in this case.
What do you think? If you can't prevent misuse by syntax you gotta increase the precautions?
std::string *str = NULL;
foo(*str);
This is undefined behavior, on the part of the caller. Not your problem. So no, you(the writer of foo) don't have to check.
Even in C, with the pointer, you don't necessarily have to check. You just have to document. "The argument must point to a valid null-terminated string. If it is not, the call is undefined behavior." -- If the user passes a NULL, that is, again, their problem. This is done all the time. If it wasn't, you'd have wasteful call chains checking the validity of the pointer at every level like this:
void foo(const char * s)
{
if (s)
printf("%s", s);
}
void bar(const char * s)
{
if (s)
foo(s);
}
void baz(const char * s)
{
if (s)
bar(s);
}
No, you're not right.
In the second code, undefined behaviour happens when you dereference your pointer, before you ever get to your function.
This is not a problem of your function. Inside your function, with the second signature you can always assume that you have a valid string, which makes it superior to the first one.
Related
Here's an (admittedly brain-dead) refactoring algorithm I've performed on several occasions:
Start with a .cpp file that compiles cleanly and (AFAICT) works correctly.
Read through the file, and wherever there is a local/stack-variable declared without the const keyword, prepend the const keyword to its declaration.
Compile the .cpp file again
If any fresh compile-time errors are reported, examine the relevant lines of code to determine why -- if it turns out the local-variable legitimately does need to be non-const, remove the const keyword from it; otherwise fix whatever underlying issue the const keyword's addition has revealed.
Goto (3) until the .cpp file again compiles cleanly
Setting aside for the moment whether or not it's a good idea to "const all the local variables", is there any risk of this practice introducing a run-time/logic error into the program that wouldn't be caught at compile-time? AFAICT this seems "safe" in that it won't introduce regressions, only compile-time errors which I can then fix right away; but C++ is a many-splendored thing so perhaps there is some risk I haven't thought of.
If you're willing to accept a contrived example, you could enter the world of undefined behavior.
void increment(int & num)
{
++num;
}
int main()
{
int n = 99;
increment(const_cast<int&>(n));
cout << n;
}
The above compiles and outputs 100. The below compiles and is allowed to do whatever it wants (but happened to output 99 for me). Modifying a const object through a non-const access path results in undefined behavior.
void increment(int & num)
{
++num;
}
int main()
{
const int n = 99;
increment(const_cast<int&>(n));
cout << n;
}
Yes, this is contrived because why would someone do a const_cast on a non-const object? On the other hand, this is a simple example. Maybe in more complex code this might actually come up. Shrug I won't claim that this is a big risk, but it does fall under "any risk", as stated in the question.
Adding const to a variable can cause a different overload to be called:
https://godbolt.org/z/aE3jzPjP3
#include <stdexcept>
void func(int &) {
}
void func(const int &) {
throw std::runtime_error("");
}
int main() {
int var = 0;
func(var);
}
Changing var to const will cause the program to call a different function and thereby throw an exception.
It can easily trigger completely different behaviour:
#include <map>
#include <iostream>
class Map {
public:
std::map<int, int> data;
int func() {
return data[5];
}
int func() const {
const auto iter = data.find(5);
return iter == data.end() ? -1 : iter->second;
}
};
int main() {
Map m; // try with const
std::cout << m.func(1) << std::endl;
std::cout << m.data.size() << std::endl;
}
const has no runtime implications, that the compiler will not tell you at compile time and fail the build.
I try to read a file decompress it and parse it to a tree in C++. Everything works fine with one excaption: For some reason I can construct a char[] string and use a pointer on it to output it with the help of cout inside a befriended overloaded <<-operator, but can't use the pointer returned by the operator to cout the string. I was thinking it might have to do with visibility of the string-memory, but that makes no sense to me since with "new" allocated memory should be visible to everyone since its on the heap of the program and not somekind of object or class heap. This all sounds rather confusing, let me show you a striped down version of the source and I'm pretty sure everything becomes clear (probably some really stupid mistake on my end... but I try since two days and don't find the mistake):
main:
#include "dekompstream.h"
#include <iostream>
int main(void) {
char *testString;
DekompStream ds(nullptr, 0);
std::cout << "TEST" << std::endl;
testString << ds;
std::cout << "Outside operator: " << testString << std::endl; // Fails misarably. Some weird randome memory-slice looking output
//delete [] testString;
return 0;
}
dekompstream.cpp:
#include "dekompstream.h"
DekompStream::DekompStream(uint8_t *kompDaten, unsigned int anzahlBytes) {
}
DekompStream::~DekompStream() {
}
uint8_t *DekompStream::dekompremieren() {
char *test = new char[4];
test[0] = 'A';
test[1] = 'B';
test[2] = 'C';
test[3] = '\0';
return (uint8_t *)test;
}
char *operator<<(char *zeichenkette, DekompStream &dekompStream) {
zeichenkette = (char *)dekompStream.dekompremieren();
std::cout << "Inside operator: " << zeichenkette << std::endl; // Works fine
return zeichenkette;
}
dekompstream.h:
#ifndef DEKOMPSTREAM_H
#define DEKOMPSTREAM_H
#include <cstdint>
#include <iostream>
class DekompStream {
public:
DekompStream(uint8_t *kompDaten, unsigned int anzahlBytes);
~DekompStream(void);
friend char *operator<<(char *zeichenkette, DekompStream &dekompStream);
private:
uint8_t *dekompremieren();
};
#endif
Thanks in advance :-)
testString << ds doesn't do what you think it does.
If we take a look at the code for operator<<:
char *operator<<(char *zeichenkette, DekompStream &dekompStream) {
zeichenkette = (char *)dekompStream.dekompremieren();
return zeichenkette;
}
The function reassigns the char* argument to a new value, then returns the new value. Fine. OK. But how does the compiler use this?
When we write:
testString << ds;
The compiler turns it into:
operator<<(testString, ds);
See the error?
You returned a new value, but because the operator overload was turned into a function call, the allocated pointer was lost. In addition, because the char* argument was simply reassigned, the original pointer value wasn't changed, meaning you got whatever was on the stack previously.
If we look at the declarations for the STL functions for iostream, we'll see the way to fix it:
ostream& operator<< (ostream& os, const char* s);
Notice the first parameter is passed by reference - this ensures any modifications to the stream made by the function persist in the calling context.
Simply change your function definition to:
char *operator<<(char *&zeichenkette, DekompStream &dekompStream){
...
}
and the issue will disappear.
I would like to be able to do the following:
std::cout << str_manip("string to manipulate");
as well as
std::string str;
str_manip(str);
std::cout << str;
For this, I have two functions
#include <string>
// copying
std::string str_manip(std::string str)
{
// manipulate str
return str;
}
// in-place
void str_manip(std::string& str)
{
// manipulate str
}
but they produce the following error:
error: call of overloaded 'str_manip(std::__cxx11::string&)' is ambiguous
How can I overcome this?
The problem is with this call:
std::string str;
str_manip(str);
std::cout << str;
The compiler doesn't know which version of str_manip to call.
You can change your functions to look like this:
#include <string>
// copying
std::string str_manip(const std::string& str)
{
std::string dup = str;
// manipulate dup
return dup;
}
// in-place
void str_manip(std::string& str)
{
// manipulate str
}
Now, the compiler knows that the ambiguous call has to be the function that takes the non-const parameter. You can also be sure that your call that returns a std::string to the << operator isn't modifying your string.
This might be not the thing you are looking for, but for your code
std::cout << str_manip("string to manipulate");
the parameter to str_manip is not a string but const char* (actually an array, but convertible to a char pointer). You can overload based on that.
std::string str_manip(const char* s)
{
std::string str(s); // create str
// manipulate str
return str;
}
However, let's look at the big picture. When you see str_manip in your code, does this mean "change the string" or "make a new string based on the given string"? Do you want to be intentionally ambivalent on the real meaning?
Consider yourself reading your code in 1 year in future. What will you think when you see a call to str_manip - does this mutate its parameter? Does the answer to the previous question depend on context?
The goal in writing code is to make it clear, especially in a multi-paradigm language like C++. So, in my opinion, just don't do overloading that you are thinking about. Instead, make 2 distinct names, like
void frobnicate_str(std::string&) {...}
std::string get_frobnicated_str(std::string) {...}
Is there a way to do something like this :
void test(char *userInput){
//code
}
char userInput = "test";
test(userInput);
I have the error : Process finished with exit code 139 so how can i proceed ?
Is there a way to do something like this :
Sure, just change your code a bit:
void test(const char *userInput){
//code
}
int main() {
const char* userInput = "test";
test(userInput);
}
I have the error : Process finished with exit code 139 so how can i proceed?
I'm pretty sure the compiler did show you some further errors before this one came up. Fix these first.
You marked this as a C++ question ... std::strings are very easy to use.
// NOTE: userinput can be either std::string OR const char*
void test(std::string userinput)
{
// code, perhaps echo testing input
std::cout << userinput << std::endl;
}
// test 290 - invoked somewhere in main
int t290(void)
{
std::string userInput = "test1";
test(userInput);
// some times you can save some typing
test("test2"); // function declared as above
// accepts both const char* or std::string
return (0);
}
As other people pointed out, there's an error in your code, char should be changed to const char*. Char only holds one value, not the entire string, and if your function takes a const value the string has also to be. Also, given you're using C++, you can use std::string wich is really straightforward to use.
I'm writing a program where I create my own string class. The program is supposed to instruct the user to write a sentence, copy the input, and then display how many characters it contains.
Although it did build and compile (using Visual Studio Express 2013), it would copy the sentence the user is instructed to write down, not display the amount of characters, and then crash.
I'm guessing is has something to do with how the memory is dynamically allocated or how *character and _String is passed between functions. But some help on how to fix this or improve my code would be very helpful.
Header: String.h
class String
{
private:
char *characters[50]; // 50 is just a placeholder to get it to work
int size;
public:
// Constructors and Destructors
String();
String(char*);
~String();
// Other functions
void stringAssign(char*);
void printString(char*);
int stringSize(char*) const;
};
Implementation: String.ccp
#include "String.h"
#include <iostream>
#include <cstring>
String::String()
{
size = 0;
* characters = 0;
}
String::String(char* _String)
{
size = stringSize(*characters + 1);
_String = new char[size];
}
String::~String()
{
delete [] *characters;
}
void String::stringAssign(char* _String)
{
_String = characters[size];
}
void String::printString(char* _String)
{
for (int i = 0; _String[i] != '\0'; i++)
std::cout << _String[i];
}
int String::stringSize(char* _String) const
{
int size;
size = strlen(*characters);
return size;
}
Test: Main.ccp
#include "String.h"
#include <iostream>
int main()
{
char string[50];
String s;
std::cout << "Enter a sentence that is less than 50 characters\n\n";
std::cin.getline(string, 50);
s.printString(string);
std::cout << s.stringSize(string);
return 0;
}
Solved:
I got the program working. Literally all I did was replace the two *character arguments with _String in the implementation. I knew it had something to do with function passing, and I did get a little help for that. But one person gave no helpful input (and practically insulted me) and both said that there were "too many things to fix". Some elaboration on the "so many things" I had to fix would be nice.
In almost all functions, you do something with the argument of the function, _String, and not with the member field characters that is supposed to hold the string internally. So your functions do not change the string at all, but rather try to mess with something you passed them.
An example
struct Foo {
char internal[42];
void bar(char *external) { external[0] = 'X'; }
void qux(char *external) { internal[0] = 'Z'; }
};
int main() {
Foo foo;
char something[6] = "Hello";
foo.qux(something); // Did something to the member variable foo.internal; variable something is unchanged.
foo.bar(something); // Now something reads "Xello", foo.internal was not changed.
}
Your code does almost as the function bar while it should work like qux.
There is indeed too much to fix in this code.
Just in case you were mistaken... Unlike some other languages, say Python or Smalltalk, C++ passes a pointer to the current object implicitly via this.