Related
I'm trying to compare a character array against a string like so:
const char *var1 = " ";
var1 = getenv("myEnvVar");
if(var1 == "dev")
{
// do stuff
}
This if statement never validates as true... when I output var1 it is "dev", I was thinking maybe it has something to do with a null terminated string, but the strlen of "dev" and var1 are equal... I also thought maybe var1 == "dev" was comparing "dev" against the memory location of var1 instead of the value. *var1 == "dev" results in an error.... tried many things, probably a simple solution for the saavy c++ developer (I havent coded c++ in a looong time).
edit:
we've tried
if(strcmp(var1, "dev") == 0)
and
if(strncmp(var1, "dev", 3) == 0)
Thanks
edit: After testing at home I'm just going to suggest my co-worker changes the datatype to a string. I believe he was comparing a char array of a large size against a string. I put together a program that outputs sizeof, strlen, etc to help us work through it. Thanks to everyone for the help.
Use strcmp() to compare the contents of strings:
if (strcmp(var1, "dev") == 0) {
}
Explanation: in C, a string is a pointer to a memory location which contains bytes. Comparing a char* to a char* using the equality operator won't work as expected, because you are comparing the memory locations of the strings rather than their byte contents. A function such as strcmp() will iterate through both strings, checking their bytes to see if they are equal. strcmp() will return 0 if they are equal, and a non-zero value if they differ. For more details, see the manpage.
You're not working with strings. You're working with pointers.
var1 is a char pointer (const char*). It is not a string. If it is null-terminated, then certain C functions will treat it as a string, but it is fundamentally just a pointer.
So when you compare it to a char array, the array decays to a pointer as well, and the compiler then tries to find an operator == (const char*, const char*).
Such an operator does exist. It takes two pointers and returns true if they point to the same address. So the compiler invokes that, and your code breaks.
IF you want to do string comparisons, you have to tell the compiler that you want to deal with strings, not pointers.
The C way of doing this is to use the strcmp function:
strcmp(var1, "dev");
This will return zero if the two strings are equal. (It will return a value greater than zero if the left-hand side is lexicographically greater than the right hand side, and a value less than zero otherwise.)
So to compare for equality you need to do one of these:
if (!strcmp(var1, "dev")){...}
if (strcmp(var1, "dev") == 0) {...}
However, C++ has a very useful string class. If we use that your code becomes a fair bit simpler. Of course we could create strings from both arguments, but we only need to do it with one of them:
std::string var1 = getenv("myEnvVar");
if(var1 == "dev")
{
// do stuff
}
Now the compiler encounters a comparison between string and char pointer. It can handle that, because a char pointer can be implicitly converted to a string, yielding a string/string comparison. And those behave exactly as you'd expect.
In this code you are not comparing string values, you are comparing pointer values. If you want to compare string values you need to use a string comparison function such as strcmp.
if ( 0 == strcmp(var1, "dev")) {
..
}
"dev" is not a string it is a const char * like var1. Thus you are indeed comparing the memory adresses. Being that var1 is a char pointer, *var1 is a single char (the first character of the pointed to character sequence to be precise). You can't compare a char against a char pointer, which is why that did not work.
Being that this is tagged as c++, it would be sensible to use std::string instead of char pointers, which would make == work as expected. (You would just need to do const std::string var1 instead of const char *var1.
There is more stable function, also gets rid of string folding.
// Add to C++ source
bool string_equal (const char* arg0, const char* arg1)
{
/*
* This function wraps string comparison with string pointers
* (and also works around 'string folding', as I said).
* Converts pointers to std::string
* for make use of string equality operator (==).
* Parameters use 'const' for prevent possible object corruption.
*/
std::string var0 = (std::string) arg0;
std::string var1 = (std::string) arg1;
if (var0 == var1)
{
return true;
}
else
{
return false;
}
}
And add declaration to header
// Parameters use 'const' for prevent possible object corruption.
bool string_equal (const char* arg0, const char* arg1);
For usage, just place an 'string_equal' call as condition of if (or ternary) statement/block.
if (string_equal (var1, "dev"))
{
// It is equal, do what needed here.
}
else
{
// It is not equal, do what needed here (optional).
}
Source: sinatramultimedia/fl32 codec (it's written by myself)
your thinking about this program below
#include <stdio.h>
#include <string.h>
int main ()
{
char str[][5] = { "R2D2" , "C3PO" , "R2A6" };
int n;
puts ("Looking for R2 astromech droids...");
for (n=0 ; n<3 ; n++)
if (strncmp (str[n],"R2xx",2) == 0)
{
printf ("found %s\n",str[n]);
}
return 0;
}
//outputs:
//
//Looking for R2 astromech droids...
//found R2D2
//found R2A6
when you should be thinking about inputting something into an array & then use strcmp functions like the program above ... check out a modified program below
#include <iostream>
#include<cctype>
#include <string.h>
#include <string>
using namespace std;
int main()
{
int Students=2;
int Projects=3, Avg2=0, Sum2=0, SumT2=0, AvgT2=0, i=0, j=0;
int Grades[Students][Projects];
for(int j=0; j<=Projects-1; j++){
for(int i=0; i<=Students; i++) {
cout <<"Please give grade of student "<< j <<"in project "<< i << ":";
cin >> Grades[j][i];
}
Sum2 = Sum2 + Grades[i][j];
Avg2 = Sum2/Students;
}
SumT2 = SumT2 + Avg2;
AvgT2 = SumT2/Projects;
cout << "avg is : " << AvgT2 << " and sum : " << SumT2 << ":";
return 0;
}
change to string except it only reads 1 input and throws the rest out
maybe need two for loops and two pointers
#include <cstring>
#include <iostream>
#include <string>
#include <stdio.h>
using namespace std;
int main()
{
char name[100];
//string userInput[26];
int i=0, n=0, m=0;
cout<<"your name? ";
cin>>name;
cout<<"Hello "<<name<< endl;
char *ptr=name;
for (i = 0; i < 20; i++)
{
cout<<i<<" "<<ptr[i]<<" "<<(int)ptr[i]<<endl;
}
int length = 0;
while(name[length] != '\0')
{
length++;
}
for(n=0; n<4; n++)
{
if (strncmp(ptr, "snit", 4) == 0)
{
cout << "you found the snitch " << ptr[i];
}
}
cout<<name <<"is"<<length<<"chars long";
}
I'm trying to compare a character array against a string like so:
const char *var1 = " ";
var1 = getenv("myEnvVar");
if(var1 == "dev")
{
// do stuff
}
This if statement never validates as true... when I output var1 it is "dev", I was thinking maybe it has something to do with a null terminated string, but the strlen of "dev" and var1 are equal... I also thought maybe var1 == "dev" was comparing "dev" against the memory location of var1 instead of the value. *var1 == "dev" results in an error.... tried many things, probably a simple solution for the saavy c++ developer (I havent coded c++ in a looong time).
edit:
we've tried
if(strcmp(var1, "dev") == 0)
and
if(strncmp(var1, "dev", 3) == 0)
Thanks
edit: After testing at home I'm just going to suggest my co-worker changes the datatype to a string. I believe he was comparing a char array of a large size against a string. I put together a program that outputs sizeof, strlen, etc to help us work through it. Thanks to everyone for the help.
Use strcmp() to compare the contents of strings:
if (strcmp(var1, "dev") == 0) {
}
Explanation: in C, a string is a pointer to a memory location which contains bytes. Comparing a char* to a char* using the equality operator won't work as expected, because you are comparing the memory locations of the strings rather than their byte contents. A function such as strcmp() will iterate through both strings, checking their bytes to see if they are equal. strcmp() will return 0 if they are equal, and a non-zero value if they differ. For more details, see the manpage.
You're not working with strings. You're working with pointers.
var1 is a char pointer (const char*). It is not a string. If it is null-terminated, then certain C functions will treat it as a string, but it is fundamentally just a pointer.
So when you compare it to a char array, the array decays to a pointer as well, and the compiler then tries to find an operator == (const char*, const char*).
Such an operator does exist. It takes two pointers and returns true if they point to the same address. So the compiler invokes that, and your code breaks.
IF you want to do string comparisons, you have to tell the compiler that you want to deal with strings, not pointers.
The C way of doing this is to use the strcmp function:
strcmp(var1, "dev");
This will return zero if the two strings are equal. (It will return a value greater than zero if the left-hand side is lexicographically greater than the right hand side, and a value less than zero otherwise.)
So to compare for equality you need to do one of these:
if (!strcmp(var1, "dev")){...}
if (strcmp(var1, "dev") == 0) {...}
However, C++ has a very useful string class. If we use that your code becomes a fair bit simpler. Of course we could create strings from both arguments, but we only need to do it with one of them:
std::string var1 = getenv("myEnvVar");
if(var1 == "dev")
{
// do stuff
}
Now the compiler encounters a comparison between string and char pointer. It can handle that, because a char pointer can be implicitly converted to a string, yielding a string/string comparison. And those behave exactly as you'd expect.
In this code you are not comparing string values, you are comparing pointer values. If you want to compare string values you need to use a string comparison function such as strcmp.
if ( 0 == strcmp(var1, "dev")) {
..
}
"dev" is not a string it is a const char * like var1. Thus you are indeed comparing the memory adresses. Being that var1 is a char pointer, *var1 is a single char (the first character of the pointed to character sequence to be precise). You can't compare a char against a char pointer, which is why that did not work.
Being that this is tagged as c++, it would be sensible to use std::string instead of char pointers, which would make == work as expected. (You would just need to do const std::string var1 instead of const char *var1.
There is more stable function, also gets rid of string folding.
// Add to C++ source
bool string_equal (const char* arg0, const char* arg1)
{
/*
* This function wraps string comparison with string pointers
* (and also works around 'string folding', as I said).
* Converts pointers to std::string
* for make use of string equality operator (==).
* Parameters use 'const' for prevent possible object corruption.
*/
std::string var0 = (std::string) arg0;
std::string var1 = (std::string) arg1;
if (var0 == var1)
{
return true;
}
else
{
return false;
}
}
And add declaration to header
// Parameters use 'const' for prevent possible object corruption.
bool string_equal (const char* arg0, const char* arg1);
For usage, just place an 'string_equal' call as condition of if (or ternary) statement/block.
if (string_equal (var1, "dev"))
{
// It is equal, do what needed here.
}
else
{
// It is not equal, do what needed here (optional).
}
Source: sinatramultimedia/fl32 codec (it's written by myself)
your thinking about this program below
#include <stdio.h>
#include <string.h>
int main ()
{
char str[][5] = { "R2D2" , "C3PO" , "R2A6" };
int n;
puts ("Looking for R2 astromech droids...");
for (n=0 ; n<3 ; n++)
if (strncmp (str[n],"R2xx",2) == 0)
{
printf ("found %s\n",str[n]);
}
return 0;
}
//outputs:
//
//Looking for R2 astromech droids...
//found R2D2
//found R2A6
when you should be thinking about inputting something into an array & then use strcmp functions like the program above ... check out a modified program below
#include <iostream>
#include<cctype>
#include <string.h>
#include <string>
using namespace std;
int main()
{
int Students=2;
int Projects=3, Avg2=0, Sum2=0, SumT2=0, AvgT2=0, i=0, j=0;
int Grades[Students][Projects];
for(int j=0; j<=Projects-1; j++){
for(int i=0; i<=Students; i++) {
cout <<"Please give grade of student "<< j <<"in project "<< i << ":";
cin >> Grades[j][i];
}
Sum2 = Sum2 + Grades[i][j];
Avg2 = Sum2/Students;
}
SumT2 = SumT2 + Avg2;
AvgT2 = SumT2/Projects;
cout << "avg is : " << AvgT2 << " and sum : " << SumT2 << ":";
return 0;
}
change to string except it only reads 1 input and throws the rest out
maybe need two for loops and two pointers
#include <cstring>
#include <iostream>
#include <string>
#include <stdio.h>
using namespace std;
int main()
{
char name[100];
//string userInput[26];
int i=0, n=0, m=0;
cout<<"your name? ";
cin>>name;
cout<<"Hello "<<name<< endl;
char *ptr=name;
for (i = 0; i < 20; i++)
{
cout<<i<<" "<<ptr[i]<<" "<<(int)ptr[i]<<endl;
}
int length = 0;
while(name[length] != '\0')
{
length++;
}
for(n=0; n<4; n++)
{
if (strncmp(ptr, "snit", 4) == 0)
{
cout << "you found the snitch " << ptr[i];
}
}
cout<<name <<"is"<<length<<"chars long";
}
I tried to write a script that removes extra white spaces but I didn't manage to finish it.
Basically I want to transform abc sssd g g sdg gg gf into abc sssd g g sdg gg gf.
In languages like PHP or C#, it would be very easy, but not in C++, I see. This is my code:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
#include <unistd.h>
#include <string.h>
char* trim3(char* s) {
int l = strlen(s);
while(isspace(s[l - 1])) --l;
while(* s && isspace(* s)) ++s, --l;
return strndup(s, l);
}
char *str_replace(char * t1, char * t2, char * t6)
{
char*t4;
char*t5=(char *)malloc(10);
memset(t5, 0, 10);
while(strstr(t6,t1))
{
t4=strstr(t6,t1);
strncpy(t5+strlen(t5),t6,t4-t6);
strcat(t5,t2);
t4+=strlen(t1);
t6=t4;
}
return strcat(t5,t4);
}
void remove_extra_whitespaces(char* input,char* output)
{
char* inputPtr = input; // init inputPtr always at the last moment.
int spacecount = 0;
while(*inputPtr != '\0')
{
char* substr;
strncpy(substr, inputPtr+0, 1);
if(substr == " ")
{
spacecount++;
}
else
{
spacecount = 0;
}
printf("[%p] -> %d\n",*substr,spacecount);
// Assume the string last with \0
// some code
inputPtr++; // After "some code" (instead of what you wrote).
}
}
int main(int argc, char **argv)
{
printf("testing 2 ..\n");
char input[0x255] = "asfa sas f f dgdgd dg ggg";
char output[0x255] = "NO_OUTPUT_YET";
remove_extra_whitespaces(input,output);
return 1;
}
It doesn't work. I tried several methods. What I am trying to do is to iterate the string letter by letter and dump it in another string as long as there is only one space in a row; if there are two spaces, don't write the second character to the new string.
How can I solve this?
There are already plenty of nice solutions. I propose you an alternative based on a dedicated <algorithm> meant to avoid consecutive duplicates: unique_copy():
void remove_extra_whitespaces(const string &input, string &output)
{
output.clear(); // unless you want to add at the end of existing sring...
unique_copy (input.begin(), input.end(), back_insert_iterator<string>(output),
[](char a,char b){ return isspace(a) && isspace(b);});
cout << output<<endl;
}
Here is a live demo. Note that I changed from c style strings to the safer and more powerful C++ strings.
Edit: if keeping c-style strings is required in your code, you could use almost the same code but with pointers instead of iterators. That's the magic of C++. Here is another live demo.
Here's a simple, non-C++11 solution, using the same remove_extra_whitespace() signature as in the question:
#include <cstdio>
void remove_extra_whitespaces(char* input, char* output)
{
int inputIndex = 0;
int outputIndex = 0;
while(input[inputIndex] != '\0')
{
output[outputIndex] = input[inputIndex];
if(input[inputIndex] == ' ')
{
while(input[inputIndex + 1] == ' ')
{
// skip over any extra spaces
inputIndex++;
}
}
outputIndex++;
inputIndex++;
}
// null-terminate output
output[outputIndex] = '\0';
}
int main(int argc, char **argv)
{
char input[0x255] = "asfa sas f f dgdgd dg ggg";
char output[0x255] = "NO_OUTPUT_YET";
remove_extra_whitespaces(input,output);
printf("input: %s\noutput: %s\n", input, output);
return 1;
}
Output:
input: asfa sas f f dgdgd dg ggg
output: asfa sas f f dgdgd dg ggg
Since you use C++, you can take advantage of standard-library features designed for that sort of work. You could use std::string (instead of char[0x255]) and std::istringstream, which will replace most of the pointer arithmetic.
First, make a string stream:
std::istringstream stream(input);
Then, read strings from it. It will remove the whitespace delimiters automatically:
std::string word;
while (stream >> word)
{
...
}
Inside the loop, build your output string:
if (!output.empty()) // special case: no space before first word
output += ' ';
output += word;
A disadvantage of this method is that it allocates memory dynamically (including several reallocations, performed when the output string grows).
There are plenty of ways of doing this (e.g., using regular expressions), but one way you could do this is using std::copy_if with a stateful functor remembering whether the last character was a space:
#include <algorithm>
#include <string>
#include <iostream>
struct if_not_prev_space
{
// Is last encountered character space.
bool m_is = false;
bool operator()(const char c)
{
// Copy if last was not space, or current is not space.
const bool ret = !m_is || c != ' ';
m_is = c == ' ';
return ret;
}
};
int main()
{
const std::string s("abc sssd g g sdg gg gf into abc sssd g g sdg gg gf");
std::string o;
std::copy_if(std::begin(s), std::end(s), std::back_inserter(o), if_not_prev_space());
std::cout << o << std::endl;
}
You can use std::unique which reduces adjacent duplicates to a single instance according to how you define what makes two elements equal is.
Here I have defined elements as equal if they are both whitespace characters:
inline std::string& remove_extra_ws_mute(std::string& s)
{
s.erase(std::unique(std::begin(s), std::end(s), [](unsigned char a, unsigned char b){
return std::isspace(a) && std::isspace(b);
}), std::end(s));
return s;
}
inline std::string remove_extra_ws_copy(std::string s)
{
return remove_extra_ws_mute(s);
}
std::unique moves the duplicates to the end of the string and returns an iterator to the beginning of them so they can be erased.
Additionally, if you must work with low level strings then you can still use std::unique on the pointers:
char* remove_extra_ws(char const* s)
{
std::size_t len = std::strlen(s);
char* buf = new char[len + 1];
std::strcpy(buf, s);
// Note that std::unique will also retain the null terminator
// in its correct position at the end of the valid portion
// of the string
std::unique(buf, buf + len + 1, [](unsigned char a, unsigned char b){
return (a && std::isspace(a)) && (b && std::isspace(b));
});
return buf;
}
for in-place modification you can apply erase-remove technic:
#include <string>
#include <iostream>
#include <algorithm>
#include <cctype>
int main()
{
std::string input {"asfa sas f f dgdgd dg ggg"};
bool prev_is_space = true;
input.erase(std::remove_if(input.begin(), input.end(), [&prev_is_space](unsigned char curr) {
bool r = std::isspace(curr) && prev_is_space;
prev_is_space = std::isspace(curr);
return r;
}), input.end());
std::cout << input << "\n";
}
So you first move all extra spaces to the end of the string and then truncate it.
The great advantage of C++ is that is universal enough to port your code to plain-c-static strings with only few modifications:
void erase(char * p) {
// note that this ony works good when initial array is allocated in the static array
// so we do not need to rearrange memory
*p = 0;
}
int main()
{
char input [] {"asfa sas f f dgdgd dg ggg"};
bool prev_is_space = true;
erase(std::remove_if(std::begin(input), std::end(input), [&prev_is_space](unsigned char curr) {
bool r = std::isspace(curr) && prev_is_space;
prev_is_space = std::isspace(curr);
return r;
}));
std::cout << input << "\n";
}
Interesting enough remove step here is string-representation independent. It will work with std::string without modifications at all.
I have the sinking feeling that good ol' scanf will do (in fact, this is the C school equivalent to Anatoly's C++ solution):
void remove_extra_whitespaces(char* input, char* output)
{
int srcOffs = 0, destOffs = 0, numRead = 0;
while(sscanf(input + srcOffs, "%s%n", output + destOffs, &numRead) > 0)
{
srcOffs += numRead;
destOffs += strlen(output + destOffs);
output[destOffs++] = ' '; // overwrite 0, advance past that
}
output[destOffs > 0 ? destOffs-1 : 0] = '\0';
}
We exploit the fact that scanf has magical built-in space skipping capabilities. We then use the perhaps less known %n "conversion" specification which gives us the amount of chars consumed by scanf. This feature frequently comes in handy when reading from strings, like here. The bitter drop which makes this solution less-than-perfect is the strlen call on the output (there is no "how many bytes have I actually just written" conversion specifier, unfortunately).
Last not least use of scanf is easy here because sufficient memory is guaranteed to exist at output; if that were not the case, the code would become more complex due to buffering and overflow handling.
Since you are writing c-style, here's a way to do what you want.
Note that you can remove '\r' and '\n' which are line breaks (but of course that's up to you if you consider those whitespaces or not).
This function should be as fast or faster than any other alternative and no memory allocation takes place even when it's called with std::strings (I've overloaded it).
char temp[] = " alsdasdl gasdasd ee";
remove_whitesaces(temp);
printf("%s\n", temp);
int remove_whitesaces(char *p)
{
int len = strlen(p);
int new_len = 0;
bool space = false;
for (int i = 0; i < len; i++)
{
switch (p[i])
{
case ' ': space = true; break;
case '\t': space = true; break;
case '\n': break; // you could set space true for \r and \n
case '\r': break; // if you consider them spaces, I just ignore them.
default:
if (space && new_len > 0)
p[new_len++] = ' ';
p[new_len++] = p[i];
space = false;
}
}
p[new_len] = '\0';
return new_len;
}
// and you can use it with strings too,
inline int remove_whitesaces(std::string &str)
{
int len = remove_whitesaces(&str[0]);
str.resize(len);
return len; // returning len for consistency with the primary function
// but u can return std::string instead.
}
// again no memory allocation is gonna take place,
// since resize does not not free memory because the length is either equal or lower
If you take a brief look at the C++ Standard library, you will notice that a lot C++ functions that return std::string, or other std::objects are basically a wrapper to a well written extern "C" function. So don't be afraid to use C functions in C++ applications, if they are well written and you can overload them to support std::strings and such.
For example, in Visual Studio 2015, std::to_string is written exactly like this:
inline string to_string(int _Val)
{ // convert int to string
return (_Integral_to_string("%d", _Val));
}
inline string to_string(unsigned int _Val)
{ // convert unsigned int to string
return (_Integral_to_string("%u", _Val));
}
and _Integral_to_string is a wrapper to a C function sprintf_s
template<class _Ty> inline
string _Integral_to_string(const char *_Fmt, _Ty _Val)
{ // convert _Ty to string
static_assert(is_integral<_Ty>::value,
"_Ty must be integral");
char _Buf[_TO_STRING_BUF_SIZE];
int _Len = _CSTD sprintf_s(_Buf, _TO_STRING_BUF_SIZE, _Fmt, _Val);
return (string(_Buf, _Len));
}
Well here is a longish(but easy) solution that does not use pointers.
It can be optimized further but hey it works.
#include <iostream>
#include <string>
using namespace std;
void removeExtraSpace(string str);
int main(){
string s;
cout << "Enter a string with extra spaces: ";
getline(cin, s);
removeExtraSpace(s);
return 0;
}
void removeExtraSpace(string str){
int len = str.size();
if(len==0){
cout << "Simplified String: " << endl;
cout << "I would appreciate it if you could enter more than 0 characters. " << endl;
return;
}
char ch1[len];
char ch2[len];
//Placing characters of str in ch1[]
for(int i=0; i<len; i++){
ch1[i]=str[i];
}
//Computing index of 1st non-space character
int pos=0;
for(int i=0; i<len; i++){
if(ch1[i] != ' '){
pos = i;
break;
}
}
int cons_arr = 1;
ch2[0] = ch1[pos];
for(int i=(pos+1); i<len; i++){
char x = ch1[i];
if(x==char(32)){
//Checking whether character at ch2[i]==' '
if(ch2[cons_arr-1] == ' '){
continue;
}
else{
ch2[cons_arr] = ' ';
cons_arr++;
continue;
}
}
ch2[cons_arr] = x;
cons_arr++;
}
//Printing the char array
cout << "Simplified string: " << endl;
for(int i=0; i<cons_arr; i++){
cout << ch2[i];
}
cout << endl;
}
I don't know if this helps but this is how I did it on my homework. The only case where it might break a bit is when there is spaces at the beginning of the string EX " wor ds " In that case, it will change it to " wor ds"
void ShortenSpace(string &usrStr){
char cha1;
char cha2;
for (int i = 0; i < usrStr.size() - 1; ++i) {
cha1 = usrStr.at(i);
cha2 = usrStr.at(i + 1);
if ((cha1 == ' ') && (cha2 == ' ')) {
usrStr.erase(usrStr.begin() + 1 + i);
--i;//edit: was ++i instead of --i, made code not work properly
}
}
}
I ended up here for a slighly different problem. Since I don't know where else to put it, and I found out what was wrong, I share it here. Don't be cross with me, please.
I had some strings that would print additional spaces at their ends, while showing up without spaces in debugging. The strings where formed in windows calls like VerQueryValue(), which besides other stuff outputs a string length, as e.g. iProductNameLen in the following line converting the result to a string named strProductName:
strProductName = string((LPCSTR)pvProductName, iProductNameLen)
then produced a string with a \0 byte at the end, which did not show easily in de debugger, but printed on screen as a space. I'll leave the solution of this as an excercise, since it is not hard at all, once you are aware of this.
I'm trying to write a program that takes in two ints as command line arguments. The ints both need to be greater than 0. I understand that I need to convert from char but I have only ever done that using atoi which I now know that I shouldn't do. I've seen people use sstreams and strtol but I'm not sure how those would work in this case. What is the best way to accomplish this?
#include <iostream>
#include <string>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
const int N = 7;
const int M = 8;//N is number of lines, M number of values
//--------------
//-----Main-----
//--------------
int main(int argc, char* argv[])
{
if((argc != 0) && (argv[0] != NULL) && (argv[1] != NULL))
{
N = argv[0];
M = argv[1];
}
else
{
cout << "Invalid or no command line arguments found. Defaulting to N=7 M=8.\n\n" << endl;
}
//Blah blah blah code here
return 0;
}
In C++11 there's stoi, stol, stoll for this: http://en.cppreference.com/w/cpp/string/basic_string/stol
Those throw invalid_argument or out_of_range exceptions if the string isn't in the right format.
There's nothing particularly wrong about using atoi, except it doesn't have a mechanism to report exceptions because it's a C function. So you only have the return value - the problem is all return values of atoi are valid values, so there's no way to differentiate between the return value of 0 as the correct parsing of "0" or the failure of parsing. Also, atoi doesn't do any checks for whether the value is outside the available value range. The first problem is easy to fix by doing the check yourself, the second is more difficult because it involves actually parsing the string - which kind of defeats the point of using an external function in the first place.
You can use istringstream like this:
Pre-C++11:
int val;
std::istringstream iss(arg[i]);
iss >> val;
if (iss.fail()) {
//something went wrong
} else {
//apparently it worked
}
C++11:
int val;
std::istringstream iss(arg[i]);
iss >> val;
if(iss.fail()) {
if(!value) {
//wrong number format
} else if(value == std::numeric_limits<int>::max() ||
value == std::numeric_limits<int>::min()
{
//number too large or too small
}
} else {
//apparently it worked
}
The difference is that pre C++11, only format errors were detected (according to standard), also it wouldn't overwrite the value on error. In C++11, values are overwritten by either 0 if it's a format error or max/min if the number is too large or too small to fit into the type. Both set the fail flag on the stream to indicate errors.
In this specific case, atoi will work fine. The problem with atoi is that you can't differentiate between its returning 0 to signify an error of some sort, and its returning 0 to indicate that the input was 0.
In your case, however, a valid input must be greater than 0. You don't care whether the input was 0 or something else that couldn't be converted. Either way you're doing to set it to the default value.
As such, I'd do something like:
int convert(char *input, int default) {
int x = atoi(input);
return x==0 ? default : x;
}
if (argc > 1)
N = convert(argv[1], 7);
if (argc > 2)
M = convert(argv[2], 8);
Note that argv[0] traditionally holds the name of the program being invoked. Arguments passed on the command line are received as argv[1] through argv[argc-1].
First, you can't use const qualifier for M and N, since you will change their value:
int N = 7;
int M = 8;//N is number of lines, M number of values
Second, you don't need to check for (argv[0] != NULL) && (argv[1] != NULL), just check if argc (argument count) is greater or equal to 3:
if(argc >= 3)
Then you need to convert this into integers. If you don't want to use atoi, and if you don't have C++11 compiler you should use C++'s stringstream or C's strtol
stringstream ss;
int temp;
ss << argv[1]; // Put string into stringstream
ss >> temp; // Get integer from stringstream
// Check for the error:
if(!ss.fail())
{
M = temp;
}
// Repeat
ss.clear(); // Clear the current content!
ss << argv[2]; // Put string into stringstream
ss >> temp; // Get integer from stringstream
// Check for the error:
if(!ss.fail())
{
N = temp;
}
so, whole code will look like this:
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <sstream>
using namespace std;
int N = 7;
int M = 8;//N is number of lines, M number of values
//--------------
//-----Main-----
//--------------
int main(int argc, char* argv[])
{
if(argc >= 3)
{
stringstream ss;
int temp;
ss << argv[1]; // Put char into stringstream
ss >> temp; // Get integer from stringstream
// Check for the error:
if(!ss.fail())
{
M = temp;
}
// Repeat
// empty
ss.clear();
ss << argv[2]; // Put char into stringstream
ss >> temp; // Get integer from stringstream
// Check for the error:
if(!ss.fail())
{
N = temp;
}
cout << M << " " << N;
}
else
{
cout << "Invalid or no command line arguments found. Defaulting to N=7 M=8.\n\n" <<
endl;
}
//Blah blah blah code here
return 0;
}
Also, C header files include with c prefix, not with .h suffix (<cstdio> instead of <stdio.h>)
Is there anyway , if I enter any string , then I want to scan ASCII value of each character inside that string , if I enter "john" then I should get 4 variables getting ASCII value of each character, in C or C++
Given a string in C:
char s[] = "john";
or in C++:
std::string s = "john";
s[0] gives the numeric value of the first character, s[1] the second an so on.
If your computer uses an ASCII representation of characters (which it does, unless it's something very unusual), then these values are the ASCII codes. You can display these values numerically:
printf("%d", s[0]); // in C
std::cout << static_cast<int>(s[0]); // in C++
Being an integer type (char), you can also assign these values to variables and perform arithmetic on them, if that's what you want.
I'm not quite sure what you mean by "scan". If you're asking how to iterate over the string to process each character in turn, then in C it's:
for (char const * p = s; *p; ++p) {
// Do something with the character value *p
}
and in (modern) C++:
for (char c : s) {
// Do something with the character value c
}
If you're asking how to read the string as a line of input from the terminal, then in C it's
char s[SOME_SIZE_YOU_HOPE_IS_LARGE_ENOUGH];
fgets(s, sizeof s, stdin);
and in C++ it's
std::string s;
std::cin >> s; // if you want a single word
std::getline(std::cin, s); // if you want a whole line
If you mean something else by "scan", then please clarify.
You can simply get the ascii value of a char by casting it to type int:
char c = 'b';
int i = c; //i contains ascii value of char 'b'
Thus, in your example the code to get the ascii values of a string would look something like this:
#include <iostream>
#include <string>
using std::string;
using std::cout;
using std::endl;
int main()
{
string text = "John";
for (int i = 0; i < text.size(); i++)
{
cout << (int)text[i] << endl; //prints corresponding ascii values (one per line)
}
}
To get the corresponding char from an integer representing an entry in the ascii table, you just have to cast the int back to char again:
char c = (char)74 // c contains 'J'
The code given above was written in C++ but it basically works the same way in C (and many other languages as well I guess)
There is no way to turn a string of length 'x' into x variables. In C or C++ you can only declare a fixed number of variables. But probably you don't need to do what you are saying. Perhaps you just need an array, or most likely you just need a better way to solve whatever problem you are trying to solve. If you explain what the problem is in the first place, then I'm sure a better way can be explained.
Ya,I think there are some more better solutions are also available but this one also be helpful.
In C
#include <stdio.h>
#include <string.h>
#include <malloc.h>
int main(){
char s[]="abc";
int cnt=0;
while(1){
if(s[cnt++]==NULL)break;
}
int *a=(int *)malloc(sizeof(int)*cnt);
for(int i=0;i<cnt;i++)a[i]=s[i];
for(int i=0;i<cnt-1;i++)printf("%d\n",a[i]);
return 0;
}
In C++
#include <iostream>
#include <string>
using namespace std;
int main(){
string s="abc";
//int *a=new int[s.length()];
//for(int i=0;i<s.length();i++)a[i]=s[i];
for(int i=0;i<s.length();i++)
cout<<(int)s[i]<<endl;
return 0;
}
I hope this one will be helpful..
yeah it's very easy ..just a demo
int main()
{
char *s="hello";
while(*s!='\0')
{
printf("%c --> %d\n",*s,*s);
s++;
}
return 0;
}
But make sure your machine is supporting the ASCII value format.
In C every char has one integral value associted with it called ASCII.
Using %d format specifier you can directly print the ASCII of any char as above.
NOTE: It's better to get good book and practice this kind of program yourself.