Code
Reads from
On Windows 7 and 8 it runs fine. However, when running in XCode 4 I get EXC_BAD_ACCESS on the second iteration when someone loads a map (select "Load Map" from title).
You can download the source with the XCode project
#include <string>
#include <map>
#include <iostream>
std::map <std::string, std::string> info;
std::string* get_key_val( std::string* line )
{
std::string key_val[2];
int start, end;
start = line->find_first_not_of( " " );
end = line->find_last_of( ":" );
if( start == -1 )
{
return NULL;
}
else if( end == -1 )
{
return NULL;
}
else
{
key_val[0] = line->substr( start, end - start );
}
start = line->find_first_not_of(" ", end + 1);
end = line->find_last_of( " \n\r" );
if( start == -1 )
{
return NULL;
}
else if( end == -1 )
{
return NULL;
}
else
{
key_val[1] = line->substr( start, end - start );
}
return key_val;
}
void parse_from_line( std::string* line )
{
std::string* keyv = get_key_val( line );
if( keyv[0].empty() == false && keyv[1].empty() == false ) info[ keyv[0] ] = keyv[1];
}
int main( int argc, char* args[] )
{
std::string line = "name: Foo";
parse_from_line( &line );
std::cout << "Hello " << info["name"].c_str();
}
Your get_key_val function starts like this:
std::string* Map::get_key_val( std::string* line )
{
std::string key_val[2];
It ends like this:
return key_val;
}
You're returning a pointer to a stack variable. The key_val variable ceases to exist upon return from the function, so you have an invalid pointer, and the two string values in the array get destroyed. Subsequent behavior is undefined.
With move semantics in C++11 onwards, its less necessary to do this. You can just return std::string and the move operator should avoid any wasteful copies.
Related
I have the code below which I would like to run it from a bash script in ubuntu. Inside my bash script, I wrote the command below.
$DOANTS/SmoothImage $216*512*512 $RESULTS/Registration/NiftyReg/StructureGuided/Pat28_MLAF0113_pv_Aff_BSpline_Iso_ArgMax.nii.gz $1 $RESULTS/Registration/NiftyReg/StructureGuided/Pat28_${CASES[$i]}\_Prostate_Aff_BSpline_Iso_ArgMax_smoothed.nii.gz
but I get the following error:
Unsupported dimension
I am not sure why the dimension is not passed. would be thankful if you could let me know the reason. The true size of image is. 216*512*512
The code is as below:
#include "antsUtilities.h"
#include <algorithm>
#include "itkMedianImageFilter.h"
#include "itkDiscreteGaussianImageFilter.h"
#include "ReadWriteData.h"
namespace ants
{
template <unsigned int ImageDimension>
int SmoothImage(int argc, char *`1 [])
{
typedef float PixelType;
typedef itk::Image<PixelType, ImageDimension> ImageType;
std::vector<float> sigmaVector = ConvertVector<float>( argv[3] );
typename ImageType::Pointer image1 = ITK_NULLPTR;
typename ImageType::Pointer varimage = ITK_NULLPTR;
ReadImage<ImageType>(image1, argv[2]);
typedef itk::DiscreteGaussianImageFilter<ImageType, ImageType> dgf;
typedef itk::MedianImageFilter<ImageType, ImageType> medf;
typename dgf::Pointer filter = dgf::New();
typename medf::Pointer filter2 = medf::New();
bool usespacing = false;
if( argc > 5 )
{
usespacing = atoi(argv[5]);
}
bool usemedian = false;
if( argc > 6 )
{
usemedian = atoi(argv[6]);
}
if( !usespacing )
{
filter->SetUseImageSpacingOff();
}
else
{
filter->SetUseImageSpacingOn();
}
if( !usemedian )
{
if( sigmaVector.size() == 1 )
{
filter->SetVariance( vnl_math_sqr( sigmaVector[0] ) );
}
else if( sigmaVector.size() == ImageDimension )
{
typename dgf::ArrayType varianceArray;
for( unsigned int d = 0; d < ImageDimension; d++ )
{
varianceArray[d] = vnl_math_sqr( sigmaVector[d] );
}
filter->SetVariance( varianceArray );
}
else
{
std::cerr << "Incorrect sigma vector size. Must either be of size 1 or ImageDimension." << std::endl;
}
filter->SetMaximumError( 0.01f );
filter->SetInput( image1 );
filter->Update();
varimage = filter->GetOutput();
}
else
{
typename ImageType::SizeType rad;
if( sigmaVector.size() == 1 )
{
rad.Fill( static_cast<unsigned long>( sigmaVector[0] ) );
}
else if( sigmaVector.size() == ImageDimension )
{
for( unsigned int d = 0; d < ImageDimension; d++ )
{
rad[d] = sigmaVector[d];
}
}
else
{
std::cerr << "Incorrect sigma vector size. Must either be of size 1 or ImageDimension." << std::endl;
}
filter2->SetRadius(rad);
filter2->SetInput( image1 );
filter2->Update();
varimage = filter2->GetOutput();
}
WriteImage<ImageType>( varimage, argv[4] );
return EXIT_SUCCESS;
}
// entry point for the library; parameter 'args' is equivalent to 'argv' in (argc,argv) of commandline parameters to
// 'main()'
int SmoothImage( std::vector<std::string> args, std::ostream* /*out_stream = NULL */ )
{
// put the arguments coming in as 'args' into standard (argc,argv) format;
// 'args' doesn't have the command name as first, argument, so add it manually;
// 'args' may have adjacent arguments concatenated into one argument,
// which the parser should handle
args.insert( args.begin(), "SmoothImage" );
int argc = args.size();
char* * argv = new char *[args.size() + 1];
for( unsigned int i = 0; i < args.size(); ++i )
{
// allocate space for the string plus a null character
argv[i] = new char[args[i].length() + 1];
std::strncpy( argv[i], args[i].c_str(), args[i].length() );
// place the null character in the end
argv[i][args[i].length()] = '\0';
}
argv[argc] = ITK_NULLPTR;
// class to automatically cleanup argv upon destruction
class Cleanup_argv
{
public:
Cleanup_argv( char* * argv_, int argc_plus_one_ ) : argv( argv_ ), argc_plus_one( argc_plus_one_ )
{
}
~Cleanup_argv()
{
for( unsigned int i = 0; i < argc_plus_one; ++i )
{
delete[] argv[i];
}
delete[] argv;
}
private:
char* * argv;
unsigned int argc_plus_one;
};
Cleanup_argv cleanup_argv( argv, argc + 1 );
// antscout->set_stream( out_stream );
if( argc < 4 )
{
std::cout << "Usage: " << std::endl;
std::cout << argv[0]
<<
" ImageDimension image.ext smoothingsigma outimage.ext {sigma-is-in-spacing-coordinates-0/1} {medianfilter-0/1}"
<< std::endl;
std::cout << " if median, then sigma means radius of filtering " << std::endl;
std::cout << " A separate sigma can be specified for each dimension, e.g., 1.5x1x2 " << std::endl;
if( argc >= 2 &&
( std::string( argv[1] ) == std::string("--help") || std::string( argv[1] ) == std::string("-h") ) )
{
return EXIT_SUCCESS;
}
return EXIT_FAILURE;
}
switch( atoi(argv[1]) )
{
case 2:
{
return SmoothImage<2>(argc, argv);
}
break;
case 3:
{
return SmoothImage<3>(argc, argv);
}
break;
case 4:
{
return SmoothImage<4>(argc, argv);
}
break;
default:
std::cout << "Unsupported dimension" << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
} // namespace ants
enter code here
I think maybe you're making an assumption that bash does inline math on the command line. It doesn't. Try for example -
$ echo $216*512*512
$ 16*512*512
In fact, unless I'm missing some syntactic magic of which I'm unaware, the $2 is simply being interpreted as the second parameter to the parent script, as in -
$ function check() { echo $216*512*512; }
$ check fragile rock
$ rock16*512*512
See? However, I think what you've got here is a typo. The $2 was probably meant to be by itself, because the first parameter to your program is a selector that you use near the end to instantiate the templated version of your smoothing function. So, the second parameter to the calling script becomes the first parameter of SmoothImage, as in -
$DOANTS/SmoothImage $2 16*512*512 $RESULTS/Registration/NiftyReg/StructureGuided/Pat28_MLAF0113_pv_Aff_BSpline_Iso_ArgMax.nii.gz $1 $RESULTS/Registration/NiftyReg/StructureGuided/Pat28_${CASES[$i]}\_Prostate_Aff_BSpline_Iso_ArgMax_smoothed.nii.gz
If however, as you say, the size parameter is 16*512*512 or 216*512*512 as the case may be, you're still running into the problem that bash doesn't do math in that way on the command line. What you want is something like -
declare -ri size=16*512*512
# or just "let size=16*512*512", the "declare -ri" just makes it a read-only integer
$DOANTS/SmoothImage $2 $size $RESULTS/Registration/NiftyReg/StructureGuided/Pat28_MLAF0113_pv_Aff_BSpline_Iso_ArgMax.nii.gz $1 $RESULTS/Registration/NiftyReg/StructureGuided/Pat28_${CASES[$i]}\_Prostate_Aff_BSpline_Iso_ArgMax_smoothed.nii.gz
I think that's where you're headed. If you want some evidence that this works, on your bash command line, try -
$ let size=16*512*512
$ echo $size
$ 4194304
Your C++ is probably fine (though I haven't gone through it in detail, but at a glance it looks OK). The problem is your bash. If you want features like inline math, you might consider looking at Python to drive your C++ programs. Just a thought.
This question already has answers here:
How do unsigned integers work
(3 answers)
Closed 2 years ago.
I am writing a program to return first occurrence of the character and the frequency of that character in the string.
For loop in the function is executing infinite times and if condition and block is not executing even once.
What is the problem?
string::size_type find_ch(string &str,char ch,int& i_r)
{
string::size_type first=0;
for(auto i=str.size()-1;i>=0;i--)
{
cout<<"\nInside a for loop."<<endl;
if(str[i]==ch)
{
cout<<"Inside if."<<endl;
first=i+1;
i_r++;
}
}
return first;
}
This loop:
for(auto i = str.size() - 1; i>=0; i--)
will only exit when i is less than 0. But this is not a valid value for an unsigned int. The value will wrap to the maximum unsigned int, and you get an infinite loop.
Note that .size() on a std::string returns a size_t, which is basically an unsigned int type.
One way to fix this would be to cast the return type of .size() to an int, like this:
for(auto i = static_cast<int>(str.size()) - 1; i>=0; i--)
Note that it's important to do the cast before subtracting 1, otherwise you'll get the wrong answer when str is empty.
In c++20, you can avoid this issue entirely by calling the std::ssize() free function, which returns a signed version of the size.
The function definition in general is wrong.
For example if the given character is nit found then why does the function return 0 that is a valid position?
Returning the value first=i+1; will only confuse users of the function. The function shall return std::string::npos if the given character is not found.
Also it is entirely unclear why the loop starts from the end of the string while you need to return the first position of the character.
As for the infinite loop then in the loop there is used variable i that has the unsigned integer type std::string::size_type a value of which never can be negative.
for(auto i=str.size()-1;i>=0;i--)
^^^^^^^^^^^^^^^^^^^
That is the condition i >= 0 is always true by the definition.
The function should be defined the following way
std::pair<std::string::size_type, std::string::size_type> find_ch( const std::string &str, char ch )
{
auto n = str.find( ch );
std::pair<std::string::size_type, std::string::size_type> p( n, 0 );
if ( n != std::string::npos )
{
++p.second;
while ( ( n = str.find( ch, n + 1 ) ) != std::string::npos ) ++p.second;
}
return p;
}
Here is a demonstrative program.
#include <iostream>
#include <string>
#include <utility>
std::pair<std::string::size_type, std::string::size_type> find_ch( const std::string &str, char ch )
{
auto n = str.find( ch );
std::pair<std::string::size_type, std::string::size_type> p( n, 0 );
if ( n != std::string::npos )
{
++p.second;
while ( ( n = str.find( ch, n + 1 ) ) != std::string::npos ) ++p.second;
}
return p;
}
int main()
{
std::string s( "C++ is not the same as C" );
auto p = find_ch( s, 'C' );
if ( p.first != std::string::npos )
{
std::cout << p.first << ": " << p.second << '\n';
}
return 0;
}
The program output is
0: 2
If you are not allowed to use methods of the class std::string then just substitute calls of the method find in the function above to while loops as it is shown below.
#include <iostream>
#include <string>
#include <utility>
std::pair<std::string::size_type, std::string::size_type> find_ch( const std::string &str, char ch )
{
std::pair<std::string::size_type, std::string::size_type> p( std::string::npos, 0 );
std::string::size_type n = 0;
while ( n < str.size() && str[n] != ch ) ++n;
if ( n != str.size() )
{
p.first = n;
++p.second;
while ( ++n != str.size() )
{
if( str[n] == ch ) ++p.second;
}
}
return p;
}
int main()
{
std::string s( "C++ is not the same as C" );
auto p = find_ch( s, 'C' );
if ( p.first != std::string::npos )
{
std::cout << p.first << ": " << p.second << '\n';
}
return 0;
}
Here is an answer similar to #Vlad From Moscow, but uses string functions, and the algorithm std::count.
#include <algorithm>
#include <string>
#include <utility>
#include <iostream>
std::pair<int,int> find_ch(const std::string &str, char ch)
{
std::pair<int, int> ret;
auto pos = str.find_first_of(ch);
if ( pos == std::string::npos )
return {-1,0}; // not found
return { pos, std::count(str.begin() + pos, str.end(), ch) };
}
int main()
{
auto pr = find_ch("abccabc", 'b');
std::cout << "character b is at position " << pr.first << ". Character count is " << pr.second << "\n";
pr = find_ch("abccabc", 'c');
std::cout << "character c is at position " << pr.first << ". Character count is " << pr.second;
}
Output:
character b is at position 1. Character count is 2
character c is at position 2. Character count is 3
Each line of the function basically describes what is being done:
find_first_of the character in the string. If found then return that position and the std::count of that character starting at the first occurrence.
Note the brevity and self-documented way the function is written. A C++ programmer could look at that code and immediately know what it does, due to the names of the functions that are being called.
Writing loops going backwards (as you originally did) with variables incremented here and there, the programmer has to sit down and go through the code to figure out what it is doing, and what the purpose of the function is.
I've been given a class smartReverse which contains one member data which is a string called str. I have to implement a member method (without any sort of helper function which takes no parameters and returns the reversed version of str.
This is my attempt so far but this does nothing but send the first character to the end of the string. And from this point I'm pretty clueless. I know how to do this using a helper function but am not allowed to use them here.
string smartReverse::rev_recursive() const
{
if (str.length() <= 1)
return str;
char first_char = str[0];
smartReverse* remainder = new smartReverse(str.substr(1));
remainder->rev_recursive();
return remainder->getString() + first_char;
}
With memleak removed, and using rev_recursive result, the fixed version might be:
std::string smartReverse::rev_recursive() const
{
if (str.length() <= 1) {
return str;
}
char first_char = str[0];
smartReverse remainder(str.substr(1));
return remainder.rev_recursive() + first_char;
}
There is no any need to allocate an object of the type std::string dynamically. It is just a bad idea.
I do not know how the class smartReverse looks but here is its simplified version that has only one member function rev_recursive that reverses the stored string.
#include <iostream>
#include <string>
class smartReverse
{
public:
smartReverse( const std::string &s ) : s( s ) {}
std::string rev_recursive()
{
if ( s.size() < 2 ) return s;
char first = s.front(), last = s.back();
s = s.substr( 1, s.size() - 2 );
return s = last + rev_recursive() + first;
}
private:
std::string s;
};
int main()
{
smartReverse obj( "Hello Brennen Green" );
std::cout << obj.rev_recursive() << '\n';
return 0;
}
The program output is
neerG nennerB olleH
If the function shall be a constant member function then its implementation can look the following way
#include <iostream>
#include <string>
class smartReverse
{
public:
smartReverse( const std::string &s ) : s( s ) {}
std::string getString() const
{
return s;
}
std::string rev_recursive() const
{
if ( s.size() < 2 ) return s;
char first = s.front(), last = s.back();
return last + smartReverse( s.substr( 1, s.size() - 2 ) ).rev_recursive() + first;
}
private:
std::string s;
};
int main()
{
smartReverse obj( "Hello Brennen Green" );
std::cout << obj.getString() << '\n';
std::cout << obj.rev_recursive() << '\n';
return 0;
}
The program output is
Hello Brennen Green
neerG nennerB olleH
Pay attention to that the used approach is more efficient than when only one character is removed from the beginning of the string and then appended to the end because in the used approach the number of recursions is less than or equal to s.size() / 2 of the original string.
I'm creating a simple program that is going to visit a website of the users choosing so I'm using an if statement like:
If (url == "http://")
{
cout << ("Connecting to ") << url;
}
else
{
cout << ("Invalid URL");
}
And I'm wondering how I can filter out strings that doesn't start with "http://" or "https://", I'm just starting out so help would be appreciated.
A clear, but not particularly fast way, is to use (assuming url is a std::string)
if (url.substr(0, 7) != "http://" && url.substr(0, 8) != "https://"){
/*I don't start with http:// or https:// */
}
Here I'm using substr to extract the start of a std::string then using the overloaded != operator.
Note that if url is shorter than 7 or 8 characters, the behaviour is still well-defined.
You could define static const char HTTP[] = "http://" and use sizeof(HTTP) - 1 &c. so you don't hardcode the lengths, but that might be going a step too far.
For more generality you could venture into the murky world of regular expressions. See std::regex.
A possible option would be to store the known starting protocols into a vector of strings then use that vector and its fuctions as well as the strings functions to do your tests and if your url is a string object comparison is easy.
#include <string>
#include <vector>
int main {
const std::vector<std::string> urlLookUps { "http://", "https://" };
std::string url( "https://www.home.com" );
unsigned int size1 = urlLookUps[0].size();
unsigned int size2 = urlLookUps[1].size();
if ( url.compare( 0, size1, urlLookUps[0] ) == 0 ||
url.compare( 0, size2, urlLookUps[1] ) == 0 ) {
std::cout << url << std::endl;
} else {
std::cout << "Invalid Address" << std::endl;
}
return 0;
}
EDIT
You can take this to the next step and turn it into a simple function
#include <string>
#include <vector>
void testUrls( const std::string& url, const std::vector<std::string>& urlLookUps ) {
std::vector<unsigned int> sizes;
for ( unsigned int idx = 0; idx < urlLookUps.size(); ++idx ) {
sizes.push_back( urlLookUps[idx].size() );
}
bool foundIt = false;
for ( unsigned int idx = 0; idx < urlLookUps.size(); ++idx ) {
if ( url.compare( 0, sizes[idx], urlLookUps[idx] ) == 0 ) {
foundIt = true;
break;
}
}
if ( foundIt ) {
std::cout << url << std::endl;
} else {
std::cout << "Invalid URL" << std::endl;
}
} // testUrls
int main() {
const std::vector<std::string> urlLookUps { "http://", "https://" };
std::string url1( "http://www.home.com" );
std::string url2( "https://www.home.com" );
std::string url3( "htt://www.home.com" );
testUrl( url1, urlLookUps );
testUrl( url2, urlLookUps );
testUrl( url3, urlLookUps );
return 0;
} // main
This way you can pass both the URL to the function as well as a container of url protocols that the user may want to populate themselves. This way the function will search through all the strings that are saved into the vector of strings.
i have this line taken from a txt file (first line in the file):
#operation=1(create circle and add to picture) name X Y radius.
why does this code doesnt take the integer 1 and puts it into k?
Circle Circle::CreateCirc(Circle c){
int k;
ifstream myfile("cmd.txt");
if (!myfile.is_open())
cout<<"Unable to open the requested file "<<endl;
string line,line2="create circle";
for (int i=1;i<countrows();i++)
{
getline(myfile,line);
if (line.find(line2)!=string::npos)
{
istringstream ss(line);
ss>>k;
cout<<k<<endl;
}
}
return c;
}
instead im getting adress memory...help plz
Because the line doesn't start with a number. You'll need to skip over the #operation= part before extracting a number.
You should check the result of the extraction, and of getline, to help identify what's going wrong when these fail.
Also, if countrows() returns the expected number of rows in the file, then your loop would miss out the last one. Either loop from zero, or while i <= countrows(); or, if you want to process every line in the file, you could simply loop while (getline(myfile,line)).
If the actual text in the file you try to read starts with "#operation=1" and you want the number 1 from that, you can't use the simple input operator. It will read the character '#' first, which isn't a digit and so the parsing will fail and k will not be initialized. And if k is not initialized, it will be of indeterminate value, and reading that value will lead to undefined behavior and seemingly random output.
You need to check that the extraction worked:
if (ss >> k)
std::cout << k << '\n';
That won't solve your problem though, as like I said above, you can't use the simple input operator here. You need to parse the string using other methods. One way might be to find the equal character '=' and get a sub-string after that to try and extract the number.
try this:
Circle Circle::CreateCirc(Circle c){
const std::streamsize ALL = std::numeric_limits< std::streamsize >::max(); // #include <limits> needed
int k;
ifstream myfile("cmd.txt");
if (!myfile.is_open())
cout<<"Unable to open the requested file "<<endl;
for (int i=1;i<countrows(); ++i, myfile.ignore(ALL,'\n') ) // skip rest of the line
{
if( myfile.ignore(ALL,'=') >> k )
{
cout<<k<<endl;
}
else
break; // read error
}
return c;
}
EDIT: A way to do it not much bit a little closer to the way you were trying to do it using atoi() rather than streams.
#include <iostream>
#include <cstdlib> // for atoi()
int main(){
std::string str = "#operation=1(create circle and add to picture) name X Y radius.";
int k;
std::string line=str, line2="(create circle";
std::size_t fnd = line.find(line2);
if (fnd!=std::string::npos)
{
k = atoi(&str[fnd-1]); // int atoi(const char *str) == argument to integer
std::cout<< k << " " << str[fnd-1] << str[fnd] << " ";
}
}
There are a few ways to extract an integer from a string but i like to filter out the digit from the string;
#include <iostream>
int main(){
std::string str = "#operation=1(create circle and add to picture) name X Y radius.";
int k = 0;
// an array of our base10 digits to filter through and compare
const char digit[] = {'0','1','2','3','4','5','6','7','8','9'};
for(int s_filter = 0; s_filter<str.size(); ++s_filter){
for(int d_filter = 0; d_filter<10; ++d_filter){
// filter through each char in string and
// also filter through each digit before the next char
if(digit[d_filter] == str[s_filter]) {
// if so the char is equal to one of our digits
k = d_filter;// and d_filter is equal to our digit
break;
} else continue;
}
}
switch(k) {
case 1:
std::cout<< "k == 1";
// do stuff for operation 1..
return 0;
case 2:
std::cout<< "k != 1";
// do more stuff
break;
//case 3: ..etc.. etc..
default:
std::cout<< "not a digit";
return 1;
}
}
// find_num.cpp (cX) 2015 adolfo.dimare#gmail.com
// http://stackoverflow.com/questions/21115457/
#include <string> // std::string
#include <cctype> // isnum
/// Find the number in 'str' starting at position 'pos'.
/// Returns the position of the first digit of the number.
/// Returns std::string::npos when no further numbers appear within 'str'.
/// Returns std::string::npos when 'pos >= str.length()'.
size_t find_num( const std::string str, size_t pos ) {
size_t len = str.length();
bool isNegative = false;
while ( pos < len ) {
if ( isdigit(str[pos]) ) {
return ( isNegative ? pos-1 : pos );
}
else if ( str[pos]=='-' ) {
isNegative = true;
}
else {
isNegative = false;
}
++pos;
}
return std::string::npos;
}
#include <cassert> // assert()
#include <cstring> // strlen();
int main() {
std::string str;
str = "";
assert( std::string::npos == find_num( str, 0 ) );
assert( std::string::npos == find_num( str, 9 ) );
str = "#operation=1(create circle and add to picture) name X Y radius.";
assert( strlen("#operation=") == find_num( str, 0 ) );
str = "abcd 111 xyx 12.33 alpha 345.12e-23";
/// 0123456789.123456789.123456789.123456789.
assert( 5 == find_num( str, 0 ) );
assert( 13 == find_num( str, 5+3 ) );
assert( 25 == find_num( str, 20 ) );
str = "abcd-111 xyx-12.33 alpha-345.12e-23";
/// 0123456789.123456789.123456789.123456789.
assert( 4 == find_num( str, 0 ) );
assert( 12 == find_num( str, 5+3 ) );
assert( 24 == find_num( str, 20 ) );
str = "-1";
assert( 0 == find_num( str, 0 ) );
assert( 1 == find_num( str, 1 ) );
assert( std::string::npos == find_num( str, 2 ) );
assert( std::string::npos == find_num( str, strlen("-1") ) );
return 0;
}