Not sure how to exactly explain this, sorry. I'm creating a function to find the first instance of a char in an array built by a given string. I have the function to create an array from the string and loop through the array, but not sure how to put it the array into the find function.
the tester is built like
stringName("Test test test");
stringName.find("e",0); //where 0 is the starting position, so it would return 1.
int SuperString::find(char c, int start) {
// put array grabber thing here
size = *(&data + 1) - data;
for(int i = start; i < size ; i++){
if(data[i] == c){
return i;
}
}
return -1;
}
This is what I have to make the string into an array.
SuperString::SuperString(std::string str) {
size = str.size();
data = new char[size];
for (int i = 0; i < size; i++) {
data[i] = str.at(i);
}
}
This is probably something easy I'm missing, but any help is appreciated.
You are passing a string literal, specifically a const char[2], where a single char is expected. Use 'e' instead of "e":
stringName.find('e', 0);
More importantly, size = *(&data + 1) - data; will only work when data is a (reference to a) fixed array (see How does *(&arr + 1) - arr give the length in elements of array arr?). It will not work when data is a pointer to an array, as it is in your case since you are allocating the array with new char[]. You will have to keep track of the array's size separately, which you appear to be doing, except that you are not actually using the size you obtained in the SuperString constructor. Just get rid of the line in find() that is trying to re-calculate size, use the value you already have:
int SuperString::find(char c, int start) {
// size = *(&data + 1) - data; // <-- GET RID OF THIS
for(int i = start; i < size; ++i){
if (data[i] == c){
return i;
}
}
return -1;
}
That being said, Your SuperString class can be greatly simplified if you just make its data member be a std::string instead of char*, eg:
#include <string>
class SuperString {
private:
std::string data;
...
public:
SuperString(const std::string &str);
int find(char c, int start = 0);
...
};
SuperString::SuperString(const std::string &str) : data(str) {
}
int SuperString::find(char c, int start) {
return (int) data.find(c, start);
}
Related
So I'm making a function that is similar to SubStr. This is an assignment so I cannot use the actual function to do this. So far I have created a function to take a string and then get the desired substring. My problem is returning the substring. In the function when I do Substring[b] = AString[b]; the substring is empty, but if I cout from inside the function I get the desired substring. So what is wrong with my code?
Here is a working demo: http://ideone.com/4f5IpA
#include <iostream>
using namespace std;
void subsec(char AString[], char Substring[], int start, int length);
int main() {
char someString[] = "abcdefg";
char someSubString[] = "";
subsec(someString, someSubString, 1, 3);
cout << someSubString << endl;
return 0;
}
void subsec(char AString[], char Substring[], int start, int length) {
for (int b = start; b <= length; b++) {
Substring[b] = AString[b];
}
}
Maybe this does what you're looking for? It's hard to say as your initial implementation used the length parameter as more of an end position.
#include <iostream>
using namespace std;
void subsec(char AString[], char Substring[], int start, int length)
{
const int end = start + length;
int pos = 0;
for(int b = start; b < end; ++b)
{
Substring[pos++] = AString[b];
}
Substring[pos] = 0;
}
int main()
{
char someString[50] = "abcdefghijklmnopqrstuvwxyz";
char someSubString[50];
subsec(someString, someSubString, 13, 10);
cout << someSubString << endl;
return 0;
}
There are several problems with the code:
1) The char arraysomeSubString has size 1 which cannot hold the substring.
2) The subsec is not correctly implemented, you should copy to the Substring from index 0.
Also remember to add \0 at the end of the substring.
void subsec(char AString[], char *Substring, int start, int length) {
int ii = 0;
for (int jj = start; jj <= length; jj++, ii++) {
Substring[ii] = AString[jj];
}
Substring[ii] = '\0';
}
You need to allocate more than 1 byte for someSubString i.e.
char someSubString[] = "xxxxxxxxxxxxxxxxxx";
or just
char someSubString[100];
if you know the max size you'll ever need.
Either would allocate enough space for the string you're copying to it. Then, you're not doing anything about the terminating 0 either. At the end of a C-style string there needs to be a terminating null to signify end of string. Otherwise cout will print something like;
abcdefgxxxxxxx
if you initialized with x's as I indicated.
There are a few problems with your code as it stands. Firstly, as your compiler is no doubt warning you, in C++ a string literal has type const char[], not just char[].
Secondly, you need to have enough space to store your substring. A good way to do this is for your function to allocate the space it needs, and then pass back a pointer to this memory. This is the way things are typically done in C code. The only thing is that you have to remember to delete the allocated array when you're done with it. (There are other, better ways to do this in C++, with things like smart pointers and wrapper objects, but those come later :-) ).
Thirdly, you'll have a problem if you request a length which is actually longer than the passed-in string -- you'll run off the end and start copying random memory (or just crash), which is definitely not what you want. C strings are terminated with a "nul byte" -- so you need to check whether you've come across this.
Speaking of the nul, you need to make sure that your substring ends with one.
Lastly, it's not really a problem but there's no need for the start parameter, you can just pass a pointer to the middle of the array if you want to.
char* substring(const char* str, int length)
{
// Allocate memory for substring;
char* subs = new char[length+1];
// Copy characters from given string
int i = 0;
while (i < length && str[i] != '\0') {
subs[i] = str[i];
i++;
}
// Append the nul byte
subs[i] = '\0';
return subs;
}
int main()
{
const char someString[] = "foobarbaz"; // Note -- must be const in C++
char* subs = substring(someString + 3, 3);
assert(strcmp(subs, "bar") == 0);
delete subs;
}
I have been pulling my hair out on this particular issue and would like some advice. I have the following struct:
struct MqlStr // MQL String Array
{
int len;
char *string;
};
this is being passed to a function as a pointer from an external application as such:
MT4_EXPFUNC double __stdcall CheckExecutionRequests(MqlStr* RequestInfo)
within the function i am generating a number of string values that i need to assign to varies elements of the MqlStr array. the following works fine:
RequestInfo[1].string = "1";
RequestInfo[2].string = "2";
but when i use strcpy to get my generated string value into the array, it overwrites the entire array with the value i copied. for example:
string field1 = value.substr(Demark + 1, Demark2 - Demark - 1);
strncpy(RequestInfo[1].string, field1.c_str(), field1.size());
string field2 = value.substr(Demark + 1, Demark2 - Demark - 1);
strncpy(RequestInfo[2].string, field2.c_str(), field2.size());
if field1 = 1 and field2 = 2 then the entire RequestInfo[] array would be equal to 2 (the last value copied)
can someone point me in the right direction?
RequestInfo[1] = "1";
is not doing what you think. It's either
RequestInfo[1].string = "1";
if RequestInfo is a vector of MqlStr objects containing at least 2 elements, or
RequestInfo->string = "1";
if RequestInfo is a pointer to a single MqlStr object.
Have you allocated enough space for the .string pointers in your RequestInfo elements? strncpy is not allocating the space for you, use strdup for that.
You need to manage MqlStr memory in a safe manner, this can happen by using a standard container like std::string or by writing methods to allocate and deallocate the internal memory.
Here is an example of a simple class that manages its internal memory:
#include <cstdlib>
#include <iostream>
#include <string.h>
#include <sstream>
struct MqlStr
{
public:
int len;
char *string;
MqlStr() { init (); }
~MqlStr() { dealloc(); }
void assign(std::string& str) {
dealloc();
string = new char[str.length() + 1];
strncpy(string, str.c_str(), str.length());
string[str.length()] = 0;
len = str.length();
}
void dealloc() {
if(string != 0) delete [] string; init();
}
private:
void init() { string = 0; len = 0; }
MqlStr(const MqlStr &);
void operator= (const MqlStr &);
};
double CheckExecutionRequests(MqlStr* RequestInfo)
{
static int callCount = 0;
std::ostringstream stringstream; stringstream<<"callCount: "<<callCount++;
std::string field1 = stringstream.str();
RequestInfo->assign(field1);
return 1.0;
}
int main(int argc, char** argv)
{
MqlStr s[5];
std::cout<<"First call"<<std::endl;
for(unsigned i = 0; i < sizeof(s)/sizeof(s[0]); ++i)
CheckExecutionRequests(s + i);
for(unsigned i = 0; i < sizeof(s)/sizeof(s[0]); ++i)
std::cout<<"MqlStr["<<i<<"].string = "<<s[i].string<<std::endl;
std::cout<<"Second call"<<std::endl;
for(unsigned i = 0; i < sizeof(s)/sizeof(s[0]); ++i)
CheckExecutionRequests(s + i);
for(unsigned i = 0; i < sizeof(s)/sizeof(s[0]); ++i)
std::cout<<"MqlStr["<<i<<"].string = "<<s[i].string<<std::endl;
return EXIT_SUCCESS;
}
The second execution of CheckExecutionRequests with the same MqlStr instances will not corrupt the memory.
An extension to the code can be preallocation of the string size, and only reallocating the memory in the assign method if the new str.length > this.maxLength (preallocated length different from the string size).
The copy constructor and assignment operator are currently disabled, because they can cause problems if not implemented properly while managing internal memory on the heap.
A simpler solution would be to write your struct using a standard container as follows:
struct MqlStr
{
public:
std::string string;
}
And then just assign the string you get for the fields to MqlStr string.
Can someone tell me what's wrong with the following?
I'm trying to add characters to a character array. name is a pointer to a character array in the MyString class.
void MyString::add_chars(char* c)
{
if(l < strlen(c)+strlen(name))
name = resize(name, l, sizeof(c));
int i,j;
for(i=0; i<strlen(c); i++) {
name[i+l-1] = c[i];
l++;
}
}
char* MyString::resize(char* vptr, int currentsize, int extra) {
char* temp = new char[currentsize + extra];
int i;
for (i = 0; i < currentsize; i++) {
temp[i] = vptr[i];
}
vptr = temp;
return vptr;
}
And in main:
MyString g ("and");
g.add_chars("baasdf");
cout << g.get_name() << "\n";
But get_name returns "andb". How can I fix my code?
Edit:
Updated code, still same result..
void StringList::add_chars(char* c)
{
char* my_new_string = resize(name, l, sizeof(char));
if( my_new_string != NULL )
{
delete [] name;
name = my_new_string;
}
int i,j;
for(i=0; i<strlen(c); i++) {
name[i+l-1] = c[i];
l++;
}
name[l-1] = '\0';
}
char* StringList::resize(char* vptr, int currentsize, int extra) {
char* temp = new char[currentsize + extra + 1];
int i;
for (i = 0; i < currentsize; i++) {
temp[i] = vptr[i];
}
vptr = temp;
return vptr;
}
This line is wrong:
name = resize(name, l, sizeof(c));
You should not take the sizeof(char*), which your c variable is, but you should do sizeof(char) or just 1.
Also, make sure that you do +1 on the size to take care of the zero termination char at the end of your string.
How can I fix my code?
Don't fix it. Throw it away and use vector<char> or just string.
But I insist, how can I fix my code!?
OK, OK, here is how...
Get a nice debugger, for example this one.
Step carefully through the code, constantly inspecting the variables and comparing them with what you expect them to be.
When you reach the call to resize, take note of sizeof(c) (assigned to extra parameter of resize). When you realize it is not what you expected, ask yourself: what is the purpose of sizeof, and you'll understand why.
BTW, you also have a memory leak and a very poor performance due all these strlens.
Firstly, am I right in assuming that this is a learning exercise for you in learning "how to create your own string class"? C++ has already got a built-in string type which you should always prefer for the most part.
the sizeof operator yields the size (in bytes) of its operand, which in this case is c whose type is char* - it looks like what you're actually after is the length of a null-terminated character array (a "C" string") - you're already using strlen, so I'd suggest you simply want to use that again. (taking a null-terminator into account too)
name = resize(name, l, strlen(c) + 1);
Note, that your code looks as if it suffers from memory leaks. You're assigning a new value to your name variable without clearing up whatever existed there first.
if(l < strlen(c)+strlen(name))
{
char* my_new_string = resize(name, l, strlen(c));
if( my_new_string != NULL )
{
delete [] name;
name = my_new_string;
}
}
EDIT: As other replies have pointed out, there's still plenty wrong with the code which could be resolved using C++'s string and vector.
Here's one possible way you could implement add_chars
void MyString::add_chars(char* c)
{
if( c != NULL && name != NULL )
{
size_t newlength = strlen(c) + strlen(name) + 1;
char* newstring = new char[newlength];
if( newstring != NULL )
{
size_t namelength = strlen(name);
size_t remaining = newlength - namelength;
strncpy( newstring, name, newlength );
strncpy( &newstring[namelength] , c, remaining );
delete [] name;
name = newstring;
}
}
}
I am trying to do some array manipulations.
I am doing char array sorting and duplicates removal here.
Your comments are welcome. Havent done much testing and error handling here though.
#include<stdafx.h>
#include<stdlib.h>
#include<stdio.h>
#include<string>
using namespace std;
void sort(char *& arr)
{
char temp;
for(int i=0;i<strlen(arr);i++)
{
for(int j=i+1;j<strlen(arr);j++)
{
if(arr[i] > arr[j])
{
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
}
bool ispresent(char *uniqueArr, char * arr)
{
bool isfound = false;
for(int i=0;i<strlen(arr);i++)
{
for(int j=0;j<=strlen(uniqueArr);j++)
{
if(arr[i]== uniqueArr[j])
{
isfound = true;
return isfound;
}
else
isfound = false;
}
}
return isfound;
}
char * removeduplicates(char *&arr)
{
char * uniqqueArr = strdup(""); // To make this char array modifiable
int index = 0;
bool dup = false;
while(*arr!=NULL)
{
dup = ispresent(uniqqueArr, arr);
if(dup == true)
{}//do nothing
else// copy the char to new char array.
{
uniqqueArr[index] = *arr;
index++;
}
arr++;
}
return uniqqueArr;
}
int main()
{
char *arr = strdup("saaangeetha");
// if strdup() is not used , access violation writing to
//location occurs at arr[i] = arr[j].
//This makes the constant string modifiable
sort(arr);
char * uniqueArr = removeduplicates(arr);
}
If you use std::string, your code (which is actually C-Style) can be written in C++ Style in just these lines:
#include <iostream>
#include <string>
#include <algorithm>
int main() {
std::string s= "saaangeetha";
std::sort(s.begin(), s.end());
std::string::iterator it = std::unique (s.begin(), s.end());
s.resize( it - s.begin());
std::cout << s ;
return 0;
}
Output: (all duplicates removed)
aeghnst
Demo : http://ideone.com/pHpPh
If you want char* at the end, then you can do this:
const char *uniqueChars = s.c_str(); //after removing the duplicates!
If I were doing it, I think I'd do the job quite a bit differently. If you can afford to ignore IBM mainframes, I'd do something like this:
unsigned long bitset = 0;
char *arr = "saaangeetha";
char *pos;
for (pos=arr; *pos; ++pos)
if (isalpha(*pos))
bitset |= 1 << (tolower(*pos)-'a');
This associates one bit in bitset with each possible letter. It then walks through the string and for each letter in the string, sets the associated bit in bitset. To print out the letters once you're done, you'd walk through bitset and print out the associated letter if that bit was set.
If you do care about IBM mainframes, you can add a small lookup table:
static char const *letters = "abcdefghijklkmnopqrstuvwxyz";
and use strchr to find the correct position for each letter.
Edit: If you're using C++ rather than C (as the tag said when I wrote what's above), you can simplify the code a bit at the expense of using some extra storage (and probably being minutely slower):
std::string arr = "saaangeetha";
std::set<char> letters((arr.begin()), arr.end());
std::copy(letters.begin(), letters.end(), std::ostream_iterator<char>(std::cout, " "));
Note, however, that while these appear the same for the test input, they can behave differently -- the previous version screens out anything but letters (and converts them all to lower case), but this distinguishes upper from lower case, and shows all non-alphabetic characters in the output as well.
char *arr = "saangeetha";
arr is pointing to read only section where string literal saangeetha is stored. So, it cannot be modified and is the reason for access violation error. Instead you need to do -
char arr[] = "sangeetha"; // Now, the string literal can be modified because a copy is made.
I'm trying to count the number of chars in a char array including the space until the end of the string.
The following compiles but doesn't return the correct value, I'm trying to use pointer arithmetic to interate through my array.
int numberOfCharsInArray(char* array) {
int numberOfChars = 0;
while (array++ != '\0') {
numberOfChars++;
}
return numberOfChars;
}
Many thanks.
Obviously I'm trying to get the equivalent of length() from cstring but using a simple char array.
Of course if my original array wasn't null terminated this could cause a very big value to return (I guess).
To access the char pointer by the pointer you need to dereference the pointer. Currently you are
comparing array ( an address) with
'\0'
You can fix your code like:
int numberOfCharsInArray(char* array){
int numberOfChars = 0;
while (*array++){
numberOfChars++;
}
return numberOfChars;
}
The cstring function you are imitating is strlen not length.
EDIT:
To know how the condition in the while works you can see this thread.
Perhaps I'm missing something, but why not just:
int numberOfCharsInArray(char* array) {
return strlen(array);
}
...or even:
int numberOfCharsInArray(char* array) {
return std::string(array).length();
}
When you write array++ != '\0' you check if the memory address array is '\0'. Try this instead:
int numberOfCharsInArray(char* array){
int numberOfChars = 0;
while (*array != '\0'){
numberOfChars++; array++;
}
return numberOfChars;
}
Edit: Oops, codaddict was faster and his code more elegant.
static const size_t maxExpectedChars = 4 * 1024; // Max chars expected, e.g. 4K
size_t numberOfCharsInArray( char * array) {
if( !array ) { return 0; } // A non-existing string has `0` length
size_t charsSoFar = 0;
while ( *array ) {
charsSoFar += 1;
if( charsSoFar == maxExpectedChars ) { break; } // Stop runaway loop
++array;
}
return charsSoFar;
}