convert bitfield to string C++ - c++

I want to convert a bitfield to a string.
Visual Studio 2008 gives an invalid null pointer exception.
Maybe it has something to do with the size of the array. it must be 8 but the output says it is 4, but why?
class Converter
{
public:
string bitfieldToString (bool b_input[])
{
string c_conv;
int i;
for(i = 0; i < sizeof(b_input) ; i++)
{
if(b_input[i]=false){
c_conv.append("0");
}
else if (b_input[i]=true){
c_conv.append("1");
}
else c_conv = "Input is not a bitfield";break;
}
cout<<c_conv<<" "<< sizeof(b_input)<<endl;
return (0);
}
};
int main(void)
{
Converter converter;
bool b2[8] = {0,1,0,0,1,0,1,1};
converter.bitfieldToString(b2);
return (0);
}
Thank you!
Now everything works as intended.
and sorry for that dump question. I am new to C++.

The exception is because you return (0);. That's interpreted as a null pointer, used to initialise a std::string with a constructor which requires a valid pointer to a C-style string - not a null pointer.
That should be return c_conv;
The size mismatch is because b_input isn't an array. As a function parameter, bool b_input[] is a pointer. You can't pass an array to a function by value; and there's no way to determine the array size from the pointer alone. So sizeof(b_input) gives you the size of a pointer, not the array, and everything goes wrong.
There are a few options. You could pass the size as a second parameter; but that's error-prone. You could infer the size as a template argument, by taking the array by reference:
template <size_t size>
string bitfieldToString (bool (&b_input)[size])
You could use std::array or std::vector, which have handy size() member functions. (But be careful with vector<bool>, since it's a special case that doesn't always behave quite like a standard container.) Or you could use std::bitset, which has a handy to_string function that does exactly what you want.
Finally, enable your compiler's warnings - it should tell you not to use = where you mean ==. And there's not much point checking for the case of a boolean being neither true nor false. You can reduce the whole loop body to
c_conv.append(b_input[i] ? '1' : '0');

There is a lot wrong in your code.
First of all, the null pointer exception comes from return (0); at the end of the bitfieldToString fuction. You have defined it to return a string; when you return 0 instead, C++ thinks 0 is a char* pointer and will try to convert it - a NULLpointer - into a string, which will crash. You should probably be returning c_conv instead.
Second, sizeof(b_input) will always be the size of a bool pointer. On a 32-bit system it will be 4, on a 64-bit system 8. You cannot get the length of an array passed as argument with sizeof; you will need to add a length parameter to your function.
Third, inside your for loop, you are assigning to b_input[i] instead of comparing the values. Use ==, not =.
Fourth, in the last else branch, you are missing braces. Essentially, the break will always break out of the loop after the very first iteration.

Related

Calculate length of string object using pointers instead of char arrays

I'm working on an exercise to calculate the length of a string using pointers.
Here's the code I've written below:
int main() {
std::string text = "Hello World";
std::string *string_ptr = &text;
int size = 0;
//Error below: ISO C++ forbids comparison between pointer and integer [-fpermissive]
while (string_ptr != '\0') {
size++;
string_ptr++;
}
std::cout << size;
}
In a lot of examples that I've seen, the string is often a char array which I also understand is a string. However, I want to try calculate it as a string object but I'm getting the error below.
Is it possible to calculate it where the string is an object, or does it need to be a char array?
If you just want the size of the string, well, use std::string::size():
auto size = text.size();
Alternatively, you can use length(), which does the same thing.
But I'm guessing you're trying to reimplement strlen for learning purposes. In that case, there are three problems with your code.
First, you're trying to count the number of characters in the string, and that means you need a pointer to char, not a pointer to std::string. That pointer should also point to constant characters, because you're not trying to modify those characters.
Second, to get a pointer to the string's characters, use its method c_str(). Getting the address of the string just gets you a pointer to the string itself, not its contents. Most importantly, the characters pointed to by c_str() are null terminated, so it is safe to use for your purposes here. Alternatively, use data(), which has been behaving identically to c_str() since C++11.
Finally, counting those characters involves checking if the value pointed to by the pointer is '\0', so you'll need to dereference it in your loop.
Putting all of this together:
const char* string_ptr = text.c_str(); // get the characters
int size = 0;
while (*string_ptr != '\0') { // make sure you dereference the pointer
size++;
string_ptr++;
}
Of course, this assumes the string does not contain what are known as "embedded nulls", which is when there are '\0' characters before the end. std::string can contain such characters and will work correctly. In that case, your function will return a different value from what the string's size() method would, but there's no way around it.
For that reason, you should really just call size().
First things first, the problem is irrelevant. std::string::size() is a O(1) (constant time) operation, as std::string's typically store their size. Even if you need to know the length of a C-style string (aka char*), you can use strlen. (I get that this is an exercise, but I still wanted to warn you.)
Anyway, here you go:
size_t cstrSize(const char* cstr)
{
size_t size(0);
while (*cstr != '\0')
{
++size;
++cstr;
}
return size;
}
You can get the underlying C-style string (which is a pointer to the first character) of a std::string by calling std::string::c_str(). What you did was getting a pointer to the std::string object itself, and dereferencing it would just give you that object back. And yes, you need to dereference it (using the * unary operator). That is why you got an error (which was on the (string_ptr != '\0') btw).
You are totally confused here.
“text” is a std::string, that is an object with a size() method retuning the length of the string.
“string_ptr” is a pointer to a std::string, that is a pointer to an object. Since it is a pointer to an object, you don’t use text.size() to get the length, but string_ptr->size().
So first, no, you can’t compare a pointer with an integer constant, only with NULL or another pointer.
The first time you increase string_ptr it points to the memory after the variable text. At that point using *string_ptr for anything will crash.
Remember: std::string is an object.

Is this how the size() function really works in std::string?

I wrote a simple function that can get the size of a std::string class object, and I know that size() function in std::string does the same job, So I wanted to know if the size() function really works like my function or if it is more complicated? If it's more complicated, then how?
int sizeOfString(const string str) {
int i=0;
while (str[i] != '\0') {
++i;
}
return i;
}
An std::string can contain null bytes, so your sizeOfString() function will produce a different result on the following input:
std::string evil("abc\0def", 7);
As for your other question: the size() method simply reads out an internal size field, so it is always constant time, while yours is linear in the size of the string.
You can peek at the implementation of std::string::size for various implementations for yourself: libc++, MSVC, libstdc++.
No.
Firstly, a std::string can contain NUL characters that count as part of the length, so you can't use '\0' as a sentinal, in the way you would for C-strings.
Secondly, The Standard guarantees that std::string::size has constant complexity.
In practice there are a few slightly different ways to represent a std::string:
pointer to start of buffer, buffer size, length of current data - size() just has to return the length member.
pointer to start of buffer, pointer to end of current data, pointer to end of buffer - size() has to return a simple calculation.
It is different than your implementation.
Your function iterates over the string until it find a null byte. Null terminated string are how string are handled in C through char*. In C++ a string is a full object with member variables.
Specifically for C++, the size of the string is stored as part of the object, making the size() function simply read out the value of a variable.
For a interesting talk about how a string works in C++ check out this video from CppCon: https://www.youtube.com/watch?v=kPR8h4-qZdk
No. Not at all like that.
std::string actually maintains the size as one of its data member. Think of std::string as a container that keeps a pointer to the actual data(a char*) and length of that data separate.
When you call size(), it actually just returns this size, hence it's O(1).
One example to highlight it's effect in practicality will be
// WRONG IMPLEMENTATION
int wrongChangeLengthToZero(std::string& s)
{
assert(s.size() != 0);
s[0]='\';
return s.size(); // Won't return 0
}
// CORRECT
int correctChangeLengthToZero(std::string& s)
{
assert(s.size() != 0);
s.resize(0);
return s.size(); // Will return 0
}

Integers and/or array of integers into a single int array using variadic function

I'm trying to write a function, with a variable number of integer/int array parameters, that concatenates all the elements into a single 1-dimensional array. I'm struggling with one of the two scenarios where current_item turns out to be an array instead of just an integer. How can I access the individual elements of this array and assign them to pOutList?
typedef unsigned short WORD;
int PinListJoin(WORD * pOutList, ...) {
int index=0;
boolean isArray = false;
va_list next_item;
va_start(next_item, pOutList);
WORD current_item = va_arg(next_item, WORD);
int current_item_size = sizeof(current_item) / sizeof(WORD);
if (current_item_size > 1) {
isArray = true;
for (int pinidx = 0; pinidx < current_item_size; pinidx++) {
pOutList[index] = current_item;
index++;
}
}
else {
isArray = false;
pOutList[index] = current_item;
index++;
}
va_end(next_item);
return(current_item_size);
}
boolean isArray = false;
There is no boolean datatype in C++.
Also, the value of neither isArray nor index variable is ever used in the function.
typedef unsigned short WORD;
WORD current_item = va_arg(next_item, WORD);
This isn't going to work. Variadic arguments are promoted. unsigned short promotes to int (typically; on some exotic system, it might be unsigned int). Using the non-promoted type with va_arg will cause undefined behaviour. You could use a trick like this to get the correct type for any system:
using promoted_word = decltype(+WORD(0));
WORD current_item = WORD(va_arg(next_item, promoted_word));
WORD current_item = va_arg(next_item, WORD);
int current_item_size = sizeof(current_item) / sizeof(WORD);
The size of WORD divided by the size of WORD is always 1. There's no point in doing this.
I'm struggling with one of the two scenarios where current_item turns out to be an array instead of just an integer. How can I access the individual elements of this array and assign them to pOutList?
Function argument cannot be an array. But it can be a pointer to an element of an array, which I assume is what you mean. If that is the case, then you can get the pointer out of varargs like this:
WORD* current_item = va_arg(next_item, WORD*);
You can then copy the elements from array to array just like you would using any pointer to an element.
There's still two problems though: 1. There is no way of finding out the size of the array based on that pointer and 2. There is no way of finding out what type of arguments were passed (i.e. whether it was a( pointer to a)n array or an integer). You can take a look at the interface of printf for an idea of how that problem may be solved. It is solved there using a format string where those types are specified. The length of the array is solved by using a sentinel value (the null terminator character). Another approach is to pass the length as a separate argument.
More generally though: I recommend that you not use C style varargs at all in C++. It's just too easy to shoot yourself in the foot. Variadic templates are much safer and more powerful way to achieve similar things.
That said, I don't quite understand what you're attempting to do, so I cannot confirm whether it makes sense to use any form of variadics.

Switch statement using char from a string with "Error: switch quantity not an integer"

In a switch statement for C++, I believe you are allowed to use either int or char in the switch. For my purposes, I want to use a char. The char I want to use is the a char from a string. Here is my function:
#include <string>
using namespace std;
...
int calindex(string* seq)
{
int index = 0;
for(int i=0;i<seq.length();i++)
{
switch(seq[i])
{
...
}
}
return index; // index is modified within the switch statement
}
However, when I compile I get an error for the line: "switch(seq[i]" that states "switch quantity not an integer". Can anyone see what I did wrong?
switch(seq[i])
should be:
switch((*seq)[i])
You forgot to dereference the pointer first. It's trying to access the ith string. Also:
seq.length();
should be:
seq->length();
The case values in a switch statement need to be compile-time constant. The point of a switch statement is to have a sort of fast, efficient cascading if statement. The compiler does special stuff to the switch statement to make it fast, but to do that, it needs to know at compile-time what all of the cases are.
seq is a string *, not a char *, so seq[i] has type string.
In C++, string is preferred over char arrays, and likewise, references are preferred over pointers, so change the declaration of your argument to
string &seq
so that string::operator [] can take effect and return a (reference to) char.
(You can declare seq as char * too, but then that's C and not C++...)
It is correct to index the string and switch by a char value, but the problem is that you're no indexing a string, but a pointer to a string. Then you should dereference the pointer, but why don't you use a string on the first place?
You're passing a string pointer to calindex, but you treat seq as if you passed a string either by value or by reference.
In order to make your switch statement work, you need to dereference the pointer in one of two ways:
(*seq)[i]
or
seq->at(i)
Please note that the latter will throw an exception if you try to access a non-existing element, the former won't.
The problem here is passing by pointer:
int calindex(string* seq)
Why dont you use:
int calindex(string& seq)
Its more safe to do it in that way.
The most important is that you do not have to make a precondition to check if pointer is zero
With reference you would not make such a simple mistake like omitting dereferencing.

Assigning a string of characters to a char array

I Want to know why the first statements works and why not second one in c++
char a[10]="iqbal"; // it works
a="iqbal"; // does not work
Strictly speaking, an array is not a pointer! And an array ( base address of the array ) cant be a modifiable lvalue. ie it cannot appear on the left hand side of an assignment operator.Arrays decay into pointers only in certain circumstances. Read this SO post to learn when arrays decay into pointers. Here is one more nice article which explains the differences between arrays and pointers
Also read about lvalues and rvalues here so that you get an idea of things which cannot appear on the LHS of =
char a[10]="iqbal";  // it works
In this case, internally what happens is
a[0] = 'i';
a[1] = 'q';
.
.
a[5] = '\0';
So everything is fine as array[i] is a modifiable lvalue.
a="iqbal"; // does not work
Internally, this is roughly equivalent to
0x60000(Address of a, but is a simple number here ) = Address of "iqbal"
This is wrong as we cannot assign something to a number.
The char array a will be static and can not be changed if you initialize it like this. Anyway you can never assign a character string a="iqbal" in c. You have to use strncpy or memcpy for that. Otherwise you will try to overwrite the pointer to the string, and that is not what you want.
So the correct code would do something like:
char a[10];
strncpy(a, "iqbal", sizeof(a) - 1);
a[sizeof(a) - 1] = 0;
The -1 is to reserve a byte for the terminating zero. Note, you will have to check for yourself if the string is null terminated or not. Bad api. There is a strlcpy() call that does this for you but it is not included in glibc.
The first line is not a statement but a declaration with an initialization.
The second line is an expression statement with the assignment operator.
You cannot assign arrays in C.
But you can initialize an array with the elements of a string literal.
why the first statements works and why not second one in c++
Because they are different statements, almost wholly unrelated. Do not be confused by the fact that they both use the = symbol. In one case, it represents object initialization. In the other case, the assignment operator.
Your first line is legal because it is legal to initialize aggregates, including character arrays.
Your second line is not legal because it is not legal to assign to an array.
Since this is C++, may I suggest that you avoid naked arrays? For character strings use std::string. For other arrays use std::vector. If you do, you example becomes:
std::string a = "iqbal"; // it works
a="iqbal"; // so does this
When writing
char a[10]="iqbal"
You are initializing the elements of the character array a with the characters. We can do the same with int type (note that the char type gets a slightly different treatment) :
int a[10]={1,2,...};
But writing the following after declaration part would be invalid as a would be treated just like a pointer. So writing something like
a={1,2,...};
or a="iqbal"
won't be making any sense!
try:
char a[10]="iqbal";
char *my_a = a;
and work with my_a.
In C++11 you can use a lambda to do the initialization, like so:
bool test = true;
/*const*/ char a[10] = { //Aggregate initialization
[=] //capture by value
()//no parameters
{ //start lambda
switch (test) {
case true: return *"test=true"; //*"xxx" don't return a pointer, but the 'string' itself
case false: return *"test=false";
} //switch
}()}; //}, close the lambda, (), call it, }; close aggregate initialization
This comes in handy when your environment does not support std::string, like NVidia's CUDA or some strange embedded environment.
The lambda gets to be inlined, so internally it translates to char a[10] = test?"xxx":"yyy";
If you have the option to do so, you obviously want to always use std::string, because fixed sized char buffers are fundamentally a bad idea.
If you use std::string you can convert that to a char array using: chararray = mystring.c_str();. Which is useful if you insist on using printf: printf("s = %s", mystring.c_str());.
You cannot assign a string literal to a char array after the latter's declaration.
A nice, simple & effective alternative is to use std::strcpy to do so, like so:
struct S
{
char name[30];
};
S s;
std::strcpy( s.name,
"The moribunds salute you." );