Question about Null vs zero - c++

I have this function:
void ToUpper(char * S)
{
while (*S!=0)
{
*S=(*S >= 'a' && *S <= 'z')?(*S-'a'+'A'):*S;
S++;
}
}
What does it mean for *S != 0, should it be null instead?

That is checking for the end of the string which is a character which has the value of zero. It is not connected to NULL pointers in any way.

I would write it *S != '\0' as I feel that is more idiomatic, but that is really just personal style preference. You are checking for the null character (ASCII NUL).
You might also consider checking S != 0 before any of that code as the pointer itself may be null, and you don't want to dereference a null pointer.

NULL is defined differently in C and C++
in C
#define NULL 0
in C++
#define NULL (void*) 0

I like algorithms better than loops:
#include <algorithm>
#include <cstring>
#include <cctype>
void ToUpper(char* p)
{
std::transform(p, p + strlen(p), p, toupper);
}
This solution also works for character encodings where a to z aren't sequential.
Just for fun, here is an experiment that only does one iteration with algorithms:
#include <algorithm>
#include <cassert>
#include <cstring>
#include <cctype>
#include <iostream>
#include <iterator>
struct cstring_iterator : std::iterator<std::random_access_iterator_tag, char>
{
char* p;
cstring_iterator(char* p = 0) : p(p) {}
char& operator*()
{
return *p;
}
cstring_iterator& operator++()
{
++p;
return *this;
}
bool operator!=(cstring_iterator that) const
{
assert(p);
assert(!that.p);
return *p != '\0';
}
};
void ToUpper(char* p)
{
std::transform(cstring_iterator(p), cstring_iterator(),
cstring_iterator(p), toupper);
}
int main()
{
char test[] = "aloha";
ToUpper(test);
std::cout << test << std::endl;
}

NULL is a pointer while *S is the value stored at the pointer. Thankes to Dennis Ritchie, the digit 0 is acceotable as both.

Related

cpp function returning garbage string value [duplicate]

I'm a newbie in C++ learning the language and playing around. I wrote a piece of code which behavior I don't understand. Could someone explain why the code below prints out random junk and not the first character of the first string in the list (that is a).
#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
#include <ctime>
#include <climits>
#include <stdio.h>
char* str2char(std::string str)
{
char cset[str.size()+1]; // +1 for the null character
for(int i = 0; i < str.size(); i++)
{
cset[i] = str[i];
}
cset[str.size()] = '\0';
return cset;
}
int main (int argc, char * const argv[]) {
std::vector< std::string > ladontakadet;
ladontakadet.push_back("aabcbbca");
ladontakadet.push_back("abcdabcd");
ladontakadet.push_back("cbbdcdaa");
ladontakadet.push_back("aadcbdca");
ladontakadet.push_back("cccbaaab");
ladontakadet.push_back("dabccbaa");
ladontakadet.push_back("ccbdcbad");
ladontakadet.push_back("bdcbccad");
ladontakadet.push_back("ddcadccb");
ladontakadet.push_back("baccddaa");
std::string v = ladontakadet.at(0);
char *r;
r = str2char(v);
std::cout << r[0] << std::endl;
return 0;
}
Why is my returning garbage, when I'm expecting it to output a?
Thnx for any help!
P.S. The output of this code is random. It doesn't always print the same character..:S
It's because you return a pointer to a local variable, a local variable that goes out of scope when the function returns.
You are already using std::string for the argument, use it instead of the array and the return pointer.
If your aim is to pass the content of a std::string to a function modifying the content of a char*:
#include <iostream>
#include <vector>
void f(char* s) {
s[0] = 'H';
}
std::vector<char> to_vector(const std::string& s) {
return std::vector<char>(s.c_str(), s.c_str() + s.size() + 1);
}
int main(void)
{
std::string s = "_ello";
std::vector<char> t = to_vector(s);
f(t.data());
std::cout << t.data() << std::endl;
}
Your function is returning garbage because you're returning the address of a local variable which goes out of scope after your function returns. It should probably look like this:
char* str2char(const std::string &str)
{
char *const cset = new char[str.size() + 1]; // +1 for the null character
strcpy(cset, str.c_str());
return cset;
}
You will need to delete your variable r by doing delete[] r;. Ideally though you wouldn't be using raw pointers, and you would use std::string for everything, or wrap the char * in a std::unique_ptr.

C++ segmentation fault while counting character occurrences in string

I've written a simple function to count occurrences of a character in a string. The compiler is fine. However, as I try to run it, it produced a segmentation fault.
#include <iostream>
using namespace std;
// To count the number of occurences of x in p
// p is a С-style null-terminated string
int count_x(char* p, char x)
{
if (p == nullptr)
{
return 0;
}
// start the counter
int count = 0;
while (p != nullptr)
{
if (*p == x)
{
++count;
}
}
return count;
}
int main(int argc, char const *argv[])
{
char myString[] = "Hello";
cout << count_x(myString, 'l');
return 0;
}
There's two mistakes in your code:
You only ever look at the first character in the string.
The last character of a null terminated string is a null character. You're testing the pointer itself.
You need to use std::string
#include <string>
#include <algorithm>
#include <iostream>
int main()
{
std::string str = "Hello";
std::cout << std::count(str.begin(), str.end(), 'l');
}

How can I read input while it exists?

#define _CRT_SECURE_NO_WARNINGS
#include <cmath>
#include <cstdio>
#include <string>
int main(){
char s = ' ';
while (s != NULL)
{
scanf ("%c", &s);
int a = 0;
if (s == '"')
{
if (a == 0) printf("``");
else printf("''");
a = 1- a;
}
else
printf("%c", s);
}
return 0;
}
this is my code, I'm new in C++, I'm writing this for uva.onlinejudge.org. the input is some text that we don't know it's size. I wanted to know how to get input while it exists ( I tried s != NULL but the program doesn't stop and gets the last char for ever)
#include <iostream>
// ...
while ( std::cin.get(s) )
{
// your code goes here
}
BTW in your existing code, scanf should be std::scanf, etc. The standard functions are all in the std:: namespace, and may or may not also be found in the global namespace.

Recursion Segmentation Fault

#include <stdio.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <vector>
using namespace std;
enum ElementType { SIMPLEFILE, DIRECTORY, SYMBOLICLINK };
class Element{
public:
Element(){};
Element(char *name_, char *full_path_name_, ElementType element_type_, long element_size_)
: name(NULL), full_path_name(NULL), element_size(0)
{
memcpy (name,name_,strlen(name_)+1);
memcpy (full_path_name,full_path_name_,strlen(full_path_name_)+1);
element_type=element_type_;
element_size=element_size_;
};
char *name;
char *full_path_name;
ElementType element_type;
long element_size;
};
int inspect(const char *input_path, std::vector<Element>& result_element_array, long *dir_size,const char *full_path ) {
std::vector<Element> result_element_array_temp;
DIR *d;
struct dirent *dir;
struct stat buf;
char *mynamebuf=(char *)malloc(0);
int c=0;
size_t base_len = strlen(full_path);
long dir_size_temp=0;
char *full_path_temp=(char *)malloc(0);
char *full_path_dummy=(char *)malloc(0);
result_element_array_temp.reserve(1000);
d = opendir( full_path);
if( d == NULL ) {
return 1;
}
while( ( dir = readdir( d ) )) {
if( strcmp( dir->d_name, "." ) == 0 || strcmp( dir->d_name, ".." ) == 0 ) {
continue;
}
memcpy (mynamebuf,full_path,strlen(full_path)+1);
strcat(mynamebuf,(full_path[base_len - 1] == '/' ? "" : "/"));
strcat(mynamebuf,dir->d_name);
if (stat(mynamebuf, &buf) != 0) {
perror(mynamebuf);
continue;
}
if( S_ISDIR(buf.st_mode) ) {//if dir
chdir( dir->d_name );
memcpy (full_path_temp,full_path,strlen(full_path)+1);
strcat(full_path_temp,"/");
strcat(full_path_temp,dir->d_name);
(dir_size_temp)=0;
inspect( ".", result_element_array_temp, &dir_size_temp, full_path_temp );
chdir( ".." );
memcpy (full_path_dummy,full_path_temp,strlen(full_path_temp)+1);
strcat(full_path_dummy,"/");
strcat(full_path_dummy,dir->d_name);
Element element;
element.name=dir->d_name;
element.full_path_name=full_path_dummy;
element.element_type=DIRECTORY;
element.element_size=dir_size_temp;
result_element_array.push_back(element);
result_element_array.insert( result_element_array.end(), result_element_array_temp.begin(), result_element_array_temp.end() );
(*dir_size)+=(dir_size_temp);
} else if( S_ISREG(buf.st_mode)) {//if file
memcpy (full_path_dummy,full_path,strlen(full_path)+1);
strcat(full_path_dummy,"/");
strcat(full_path_dummy,dir->d_name);
Element element;
element.name=dir->d_name;
element.full_path_name=full_path_dummy;
element.element_type=SIMPLEFILE;
element.element_size=buf.st_size;
result_element_array.push_back(element);
(*dir_size)+=buf.st_size;
} else if( S_ISLNK(buf.st_mode) ) {//if link
memcpy (full_path_dummy,full_path,strlen(full_path)+1);
strcat(full_path_dummy,"/");
strcat(full_path_dummy,dir->d_name);
Element element;
element.name=dir->d_name;
element.full_path_name=full_path_dummy;
element.element_type=SIMPLEFILE;
element.element_size=buf.st_size;
result_element_array.push_back(element);
} else {
continue;
}
}
closedir(d);
return 0;
}
int main(){
std::vector<Element> result_element_array;
result_element_array.reserve(3000);
long dir_size;
const char *full_path="/";
inspect("/", result_element_array, &dir_size,full_path );
std::vector <Element>::iterator It;
for(It = result_element_array.begin(); It != result_element_array.end(); ++It){
printf("%s\n",(*It).full_path_name);
}
return 0;
}
The code is above. I aim to write directory explorer recursively.
I GDBed the code and it reaches return 0 when inspect method called recursively, but return 0 can not be executed. Might it be about stackoverflow caused by some other lines? Any idea would be appreciated.
On your Element constructor, you're memcpy-ing char arrays without allocating the destination char*. You should consider using std::string:
class Element{
public:
Element(){};
Element(char *name_,
char *full_path_name_,
ElementType element_type_,
long element_size_)
:name(name),
full_path_name(full_path_name_),
element_size(0)
{
element_type=element_type_;
element_size=element_size_;
};
std::string name;
std::string full_path_name;
ElementType element_type;
long element_size;
};
You are also performing a malloc of 0 bytes, and then use this pointer as if it was valid:
char *mynamebuf=(char *)malloc(0);
You should also consider using std::string, or at least fix it to allocate a valid amount of bytes.
Since you're using gdb I'm going to assume valgrind is available. Your use of memcpy is unsafe and valgrind should assist with finding the various memory corruption issues your program seems to have. Like Jeremy Friesner and fontanini both suggested, use std::string instead of naked char *.

c++ what is the fastest way of storing comma separated int in std::vector

I have a comma separated integers and I want to store them in std::vector<int>. Currently I am manually doing it. Is there any built-in function which did the above functionality?
Edit:
I was in hurry and forget to put full details
Actually i have string (to be exact Unicode string) containing CSvs e.g. "1,2,3,4,5"
Now i want to store them in std::vector<int> so in above case my vector would have five elements pushed into it. Currently i am doing this by manual but its slow as well as there is lot of mess with that code
It's probably not be the most efficient way, but here's a way to do it using the TR1 regex functionality (I also use C++0x lambda syntax in this sample, but obviously it could also be done without that):
#include <iostream>
#include <algorithm>
#include <vector>
#include <regex>
#include <iterator>
#include <cstdlib>
std::vector<int> GetList(const std::wstring &input)
{
std::vector<int> result;
std::wsregex_iterator::regex_type rex(L"(\\d+)(,|$)");
std::wsregex_iterator it(input.begin(), input.end(), rex);
std::transform(it, std::wsregex_iterator(), std::back_inserter(result),
[] (const std::wsregex_iterator::value_type &m)
{ return std::wcstol(m[1].str().c_str(), nullptr, 10); });
return result;
}
You can do this using purely in STL for simplicity (easy to reading, no complex libs needed), which will be fast for coding, but not the fastest in terms of execution speed (though you can probably tweak it a little, like pre-reserving space in the vector:
std::vector<int> GetValues(std::wstring s, wchar_t delim)
{
std::vector<int> v;
std::wstring i;
std::wstringstream ss(s);
while(std::getline(ss,i,delim))
{
std::wstringstream c(i);
int x;
c >> x;
v.push_back(x);
}
return v;
}
(no forwarding(&&) or atoi to keep the code portable).
Sadly, the STL doesn't allow you to split a string on a separator. You can use boost to do it though: (requires a recent C++ compiler such as MSVC 2010 or GCC 4.5)
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
using namespace std;
int main(int argc, char** argv)
{
string input = "1,2,3,4";
vector<string> strs;
boost::split(strs, input, boost::is_any_of(","));
vector<int> result;
transform(
strs.begin(), strs.end(), back_inserter(result),
[](const string& s) -> int { return boost::lexical_cast<int>(s); }
);
for (auto i = result.begin(); i != result.end(); ++i)
cout << *i << endl;
}
The quick and dirty option is to use the C string library strtok() function, and atoi():
void Split(char * string, std::vector<int>& intVec)
{
char * pNext = strtok(string, ",");
while (pNext != NULL)
{
intVec.push_back(atoi(pNext));
pNext = strtok(NULL, ",");
}
}
Insert your own input data validation as required.
See:
http://www.cplusplus.com/reference/clibrary/cstring/strtok/
http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/
As well as the wide string versions:
http://msdn.microsoft.com/en-us/library/2c8d19sb%28v=vs.71%29.aspx
http://msdn.microsoft.com/en-us/library/aa273408%28v=vs.60%29.aspx
EDIT:
Note that strtok() will modify your original string, so pass a copy if need be.
Try this:
It will read any type (that can be read with >>) separated by any char (that you choose).
Note: After the object is read there should can only be space between the object and the separator. Thus for things like ObjectSepReader<std::string, ','> it will read a word list separated by ','.
This makes it simple to use our standard algorithms:
#include <vector>
#include <sstream>
#include <iostream>
#include <iterator>
#include <algorithm>
int main()
{
std::stringstream data("1,2,3,4,5,6,7,8,9");
std::vector<int> vdata;
// Read the data from a stream
std::copy(std::istream_iterator<ObjectSepReader<int, ','> >(data),
std::istream_iterator<ObjectSepReader<int, ','> >(),
std::back_inserter(vdata)
);
// Copy data to output for testing
std::copy(vdata.begin(), vdata.end(), std::ostream_iterator<int>(std::cout," "));
}
The secret class to make it work.
template<typename T,char S>
struct ObjectSepReader
{
T value;
operator T const&() const {return value;}
};
template<typename T,char S>
std::istream& operator>>(std::istream& stream, ObjectSepReader<T,S>& data)
{
char terminator;
std::string line;
std::getline(stream, line, S);
std::stringstream linestream(line + ':');
if (!(linestream >> data.value >> terminator) || (linestream.tellg() != line.size()+1) || (terminator != ':'))
{ stream.setstate(std::ios::badbit);
}
return stream;
}
Personally I'd make a structure and have the vector contain instances of the struct.
Like so:
struct ExampleStruct
{
int a;
int b;
int c;
};
vector<ExampleStruct> structVec;
How about this?
#include <string>
#include <vector>
#include <functional>
#include <algorithm>
#include <iostream>
struct PickIntFunc
{
PickIntFunc(std::vector<int>& vecInt): _vecInt(vecInt),_pBegin(0){}
char operator () (const char& aChar)
{
if(aChar == ',' || aChar == 0)
{
_vecInt.push_back(atoi(std::string(_pBegin,&aChar).c_str()));
_pBegin = 0;
}
else
{
if(_pBegin == 0)
{
_pBegin = &aChar;
}
}
return aChar;
}
const char* _pBegin;
std::vector<int>& _vecInt;
};
int _tmain(int argc, _TCHAR* argv[])
{
std::vector<int> vecInt;
char intStr[] = "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20";
std::for_each(intStr,intStr+sizeof(intStr),PickIntFunc(vecInt));
// Now test it
std::for_each(vecInt.begin(),vecInt.end(), [] (int i) { std::cout << i << std::endl;});
return 0;
}