How to work with char* inside a class - c++

I am new to c++ and doing some self training from a text book. I need to create a new class, "String". It must use a constructor to initialize the string to a made up of a repeating character of a sepcified length.
I cannot figure out how to assign anything to a char* variable. Per the assignment I CANNOT use the standard string library to do this. What Do I need to do in my constructor?
#include "stdafx.h"
#include <cstdlib>
#include <iostream>
#include <string.h>
using namespace std;
class String {
protected:
int _len;
public:
char *buff;
String (int n, char* c);
};
int main()
{
String myString(10,'Z');
cout << myString.buff << endl;
system("PAUSE");
return 0;
}
String::String(int n, char* c)
{
buff = new char[n];
}

You're almost there: since you need repeated character, you shouldn't be passing char*, just a plain char. Also buffers of C strings need to be longer by one character than the string; the last element of the buffer must be the zero character \0.
String::String(int n, char c) {
buff = new char[n+1];
for (int i = 0 ; i != n ; buf[i++] = c)
;
buf[n] = '\0';
}
Note that making buf a public member variable is not a good idea: users of String shouldn't be able to reassign a new buffer, so providing an accessor char* c_str() and making buf private is probably a good idea.

Related

Reading string user input into an array of any size

so I'm currently trying to read user input into a char array, but every single example I've looked at defines the size of the array upon its initialization. What I'm looking for, essentially, is a way to read user input (perhaps with getline, as I would want to read user input as a string) and store it in an array.
Let's say a user inputs this into the program:
This is a string
I would want the array size to be able to fit that string, and place the null terminator after the "g". Then, another user could put a string of any size that they so desired into the program, but I would basically want my program to always make the array size just enough to contain what was read in from input.
I haven't been able to get this working and it's been a couple of hours of browsing endless pages, so any help would be appreciated! Thanks.
As Tony Delroy said on his comment (I can't comment yet), you should be using std::string.
If you really need an char array, as parameter to a function for example, you can use the function c_str() to get the content of the std::string as a const char* array or if you need a char* array, you can copy the content of the array given by c_str() to a dynamically allocated array, using
char* cstr = new char[str.length() + 1];
strcpy(cstr, str.c_str());
As an addend, you need to include the header cstring in order to use the function strcpy and need to use delete[] cstr to delete the char* when you're not going to use it anymore
#include <iostream>
#include <cstring>
using namespace std;
// string argument as std::string
void foo(string str) {
// function body
}
// argument as const char*
void bar(const char* str) {
// function body
}
// argument as char*
void baz(char* str) {
// function body
}
int main() {
string str;
getline(cin, str);
foo(str);
bar(str.c_str());
char* cstr = new char[str.length() + 1];
strcpy(cstr, str.c_str());
baz(cstr);
delete[] cstr;
return 0;
}
you should use std::string for that.
the null terminator has no use in std::string, because you can just use:
string.size()
to get the size of the user input.
if want to traverse a string like a char array one by one it should look like something like this:
std::string input;
std::getline(std::cin, input);
for (int i = 0; i < input.size() ; i++)
{
std::cout << input[i];
}

How can I declare a structure of an unknow size?

I have this structure :
struct __attribute__((packed)) BabelPacket
{
unsigned senderId;
unsigned dataLength;
unsigned char data[0];
};
And to declare it I do :
BabelPacket *packet = reinterpret_cast<BabelPacket *>(new char[sizeof(BabelPacket) + 5]);
packet->senderId = 1;
packet->data = "kappa";
packet->dataLength = 5;
But when I compile I have this error :
error: incompatible types in assignment of ‘const char [6]’ to ‘unsigned char [0]’
packet->data = "kappa";
^
Have you an idea how I can do that ?
And I need to send this structure through a socket, to get the object back in my server, so I can use only C types.
If this was a C program, the error you get is because you try to assign to an array, which is not possible. You can only copy to an array:
memcpy(packet->data, "kappa", 5);
Also note that if you want the data to be a C string, you need to allocate an extra character for the string terminator '\0'. Then you can use strcpy instead of memcpy above. Or strncpy to copy at most a specific amount of characters, but then you might need to manually terminate the string.
However, this should not work in C++ at all, unless your compiler have it as an extension.
You can't assign a literal string that way. You'll need to allocate additional memory for the string, then copy to the data pointer.
struct A {
size_t datasize;
char data[0]; // flexible member must appear last.
};
A* create_A(const char* str)
{
size_t datasize = strlen(str) + 1; // null terminated (?)
A* p = reinterpret_cast<A*>(new char[sizeof(A) + datasize]);
memcpy(p->data, str, datasize);
p->datasize = datasize;
return p;
}
A* p = create_A("data string");
This solution is only applicable in environments supporting zero-length or flexible arrays. In fact, a better solution may be to write the sockets code in C and export that interface for use in C++.
If you are willing/allowed to change the unsigned char to a regular char, you can use strcpy:
#include <iostream>
#include <stdio.h>
#include <string.h>
struct __attribute__((packed)) BabelPacket
{
unsigned senderId;
unsigned dataLength;
char data[0]; // I changed this to char in order to use strcpy
};
int main(){
BabelPacket *packet = reinterpret_cast<BabelPacket *>(new char[sizeof(BabelPacket) + 5]);
packet->senderId = 1;
// Copy the string. Add NULL character at the end of
// the string to indicate its end
strcpy(packet->data, "kappa\0");
packet->dataLength = 5;
// Verify that the string is copied properly
for (int i=0;i<packet->dataLength;++i){
std::cout<<packet->data[i];
}
std::cout<<std::endl;
return 0;
}
Note that this will only work if data is at the end of the struct, otherwise there is no contiguous memory to allocate data. If I swap the order of the elements to:
struct __attribute__((packed)) BabelPacket
{
unsigned senderId;
char data[0]; // I changed this to char in order to use strcpy
unsigned dataLength;
};
the output of the code above (instead of "kappa"), would be "a".
A more reliable way if you are determined to use C-arrays would be to assume a maximum number of elements and preallocate the array, i.e.:
#include <iostream>
#include <stdio.h>
#include <string.h>
#define MAX_NUMBER_OF_CHARACTERS 5 // Many ways to do this, I defined the macro for the purposes of this example
struct __attribute__((packed)) BabelPacket
{
unsigned senderId;
// I changed this to char in order to use strcpy. Allocate the
// max number + 1 element for the termination string
char data[MAX_NUMBER_OF_CHARACTERS+1];
unsigned dataLength;
};
int main(){
BabelPacket *packet = reinterpret_cast<BabelPacket *>(new char[sizeof(BabelPacket) + 5]);
packet->senderId = 1;
packet->dataLength = 5;
if (dataLength>MAX_NUMBER_OF_CHARACTERS){
std::cout<<"String greater than the maximum number of characters"<<std::endl;
}
// Copy the string. Add NULL character at the end of
// the string to indicate its end
strcpy(packet->data, "kappa\0");
// Verify that the string is copied properly
for (int i=0;i<packet->dataLength;++i){
std::cout<<packet->data[i];
}
std::cout<<std::endl;
return 0;
}
This code produces the correct output, and protects you against violations. As you can see, it can get messy pretty quickly, which is why I would recommend to use std::vector for this. The dataLength may then be retrieved automatically as the size of the vector, and you are always protected against overflows.

return char array from function that passes parameters

I'm working with a piece of C++ code that reads lines from a txt file and then assign each line to to an array called lines. Then it calls a function that converts each element in the lines array to a char array and then return the resulted char array. This step is where I stuck. How could I return a char array from the function toChar and assign the returned array to another array so I can use it as I need? (the rest of the code should use each returned char array to write it in a pipe, this not important right now but just to clarify why I need to learn to return an array from a function)
Here is the code I'm using:
#include <fstream>
#include <iostream>
#include <string.h>
#include <unistd.h>
#include <cstdlib>
using namespace std;
char * toChar(string line);
int main()
{
string lines[0] = "line1";
char* a = toChar(lines[0]);
return 0;
}
char * toChar(string line)
{
char a[1024];
strcpy(a, line.c_str());
return a;
}
Please note that in this code I'm trying to shrink the code so I'm assigning a simple string value to the array
when I try to compile this code, the error below appears:
warning: address of local variable 'a' returned
any help or suggestion is greatly appreciated..
First use a const & in passing the string to the function to avoid the unnecessary copying, and be able to use temporaries, e.g. toChar("I am temp");
The are the following alternatives:
(1) Return std::string
std::string toChar(std::string const & line)
{
char a[1024];
strcpy(a, line.c_str());
return a;
}
Of course it is assumed that line is smaller than 1024 chars with the null termination symbol
(2) Return an allocated array the
char * toChar(std::string const & line)
{
char * a = new char[1024];
strcpy(a, line.c_str());
return a;
}
but you will have to actually manage it and delete it later.
(3) Allocate the array and pass it to the function
void toChar(string const & line, char a[])
{
strcpy(a, line.c_str());
}
I imagine that you actually want to extract a C-string from an std::string , or some part of it. The proper way to do it is (3).
The warning is correct and practically is an error. You're declaring the char array locally so it will be deleted after going out of scope of that function and its address will be no more valid.
Since you're using c++ avoid char array and use a std::string.
If you want to access to the internal storage of your string you can call line.c_str() which returns a const char *.
Hence you won't need you function toChar that creates a local array that will go out of scope at the end of your function.
You could simply do :
int main()
{
string lines[0] = "line1";
const char* a = lines[0].c_str();
return 0;
}
But I advise you to keep manipulating std::string as they will handle string better than a simple char *.
And if you want a copy, just do it : std::string mycopy = lines[0].

Writing access violation while using qsort()

I am using qsort c++ function. I am passing wordArr in my insert function. The objective is to sort the letters for each word belonging to wordArr.However, while using qsort, I get write access violation. Please let me know, where is my mistake.
char* wordArr[]={"cat","bat","dog"};
int tableClass::compChar(const void* a, const void* b)//in my header file this is static
{
return *(const char*)a - *(const char*)b;
}
void tableClass::insert(char* wordArr[],const int size)
{
for (int i = 0; i < size; i++)
{
qsort(wordArr[i], strlen(wordArr[i]), sizeof(char),tableClass::compChar);
}
}
There are several problems with your code:
1) The parameters are wrong, look at the documentation
2) You're trying to modify read-only memory by reordering an array of pointers to strings allocated into a read-only area. That is not allowed and can result in undefined behavior, i.e. anything could happen.
I would suggest using std::sort for this kind of things and possibly use a stl vector
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;
void sort_stuff(std::vector<std::string>& arr)
{
sort(arr.begin(), arr.end());
}
bool myfunction (char *i,char *j) {
int res = strcmp(i,j); // Needed to compare all characters
return (res < 0) ? true : false; // Weak ordering criterion
}
int main() {
std::vector<std::string> arr;
arr.push_back("cat");
arr.push_back("dog");
arr.push_back("bat");
sort_stuff(arr);
// --- edit: if you really want to use a char array ---
char cat[] = "cat";
char bat[] = "bat";
char dog[] = "dog";
char* wordArr[]={cat, bat, dog};
sort(wordArr, wordArr+sizeof(wordArr)/sizeof(char*), myfunction);
cout << wordArr[0] << wordArr[1] << wordArr[2];
return 0;
}
Try it live: http://ideone.com/ErEWnb
Edit: I'm not sure why you really want to use a char array but in case you really need it, you should
1) Put those into writeable memory (e.g. local memory, not string literals)
2) Specify the comparison function since if you pass a char pointers array straight away to sort you would compare the pointers instead of the data they point to. And make sure you compare all characters of the strings. strcmp does what you want
bool myfunction (char *i,char *j) {
int res = strcmp(i,j); // Needed to compare all characters
return (res < 0) ? true : false; // Weak ordering criterion
}
...
char cat[] = "cat";
char bat[] = "bat";
char dog[] = "dog";
char* wordArr[]={cat, bat, dog};
sort(wordArr, wordArr+sizeof(wordArr)/sizeof(char*), myfunction);
cout << wordArr[0] << wordArr[1] << wordArr[2];
Your code attempts to sort the characters of each string.
char* wordArr[] = { "cat", "bat", "dog" };
Is an array of pointers to string literals. No matter that you store the location of those character literals as char* and not as char const* (which is only possible due to the wish of the c++ standards committee to preserve backwards compatibility), changing a string literal causes undefined behavior.
In your case, the storage for the string literals will be allocated in read only memory, leading to an access violation when you attempt to write it.
By storing the string literals in memory under your own control, the access violation does not happen:
char cat[] = "cat";
char bat[] = "bat";
char dog[] = "dog";
char* wordArr[]={cat, bat, dog};

C++ char* array

When I create something like
char* t = new char[44];
t = strcpy(s,t);
then strlen(t); return some wrong results. how I can change this?
Both strcpy and strlen expect to find the special character NUL or '\0' in the array. An uninitialized array, as the one you've created, may contain anything at all, which means the behavior of your program is undefined when it is passed to strcpy as the source argument.
Assuming the goal was to copy s into t, to make the program behave as expected, try this:
#include <iostream>
#include <cstring>
int main()
{
const char* s = "test string";
char* t = new char[44];
// std::strcpy(t, s); // t is the destination, s is the source!
std::strncpy(t, s, 44); // you know the size of the target, use it
std::cout << "length of the C-string in t is " << std::strlen(t) << '\n';
delete[] t;
}
But keep in mind that in C++, strings are handled as objects of type std::string.
#include <iostream>
#include <string>
int main()
{
const std::string s = "test string";
std::string t = s;
std::cout << "length of the string in t is " << t.size() << '\n';
}
What are you trying to do? Do you want to copy from s to t? If so, the arguments to strcpy are reversed.
char* t = new char[44]; // allocate a buffer
strcpy(t,s); // populate it
Such C-style string processing is a red flag, but that's all I can say given this little information.
This code might be helpful:
char * strcpy (char * destination, const char * source);
t = strcpy(t, s);
You have to initialize the variable t
Do something like this:
char *t = new char[44];
memset(t, 0, 44);
// strlen(t) = 0
The strcpy function is described thus:
#include <string.h>
char *strcpy(char *dest, const char *src);
The strcpy() function copies the string pointed to by src (including the terminating '\0' character) to the array pointed to by dest.
So, if you are trying to fill in your newly allocated array, you should be doing:
strcpy(t, s);
Not the other way around.