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;
}
Related
#include<string>
#include<cstring>
class Solution {
void shift_left(char* c, const short unsigned int bits) {
const unsigned short int size = sizeof(c);
memmove(c, c+bits, size - bits);
memset(c+size-bits, 0, bits);
}
public:
string longestPalindrome(string s) {
char* output = new char[s.length()];
output[0] = s[0];
string res = "";
char* n = output;
auto e = s.begin() + 1;
while(e != s.end()) {
char letter = *e;
char* c = n;
(*++n) = letter;
if((letter != *c) && (c == &output[0] || letter != (*--c)) ) {
++e;
continue;
}
while((++e) != s.end() && c != &output[0]) {
if((letter = *e) != (*--c)) {
const unsigned short int bits = c - output + 1;
shift_left(output, bits);
n -= bits;
break;
}
(*++n) = letter;
}
string temp(output);
res = temp.length() > res.length()? temp : res;
shift_left(output, 1);
--n;
}
return res;
}
};
input string longestPalindrome("babad");
the program works fine and prints out "bab" as the longest palindrome but there's a heap overflow somewhere. Error like this appears:
Read of size 6 at ...memory address... thread T0
"babad" is size 5 and after going over this for an hour. I don't see the point where the iteration ever exceeds 5
There is 3 pointers here that iterate.
e as the element of string s.
n which is the pointer to the next char of output.
and c which is a copy of n and decrements until it reaches the address of &output[0].
maybe it's something with the memmove or memset since I've never used it before.
I'm completely lost
TL;DR : mixture of char* and std::string are not really good idea if you don't understand how exactly it works.
If you want to length of string you cant do this const unsigned short int size = sizeof(c); (sizeof will return size of pointer (which is commonly 4 on 32-bit machine and 8 on 64-bit machine). You must do this instead: const size_t size = strlen(c);
Address sanitizers is right that you (indirectly) are trying to get an memory which not belongs to you.
How does constructor of string from char* works?
Answer: char* is considered as c-style string, which means that it must be null '\0' terminated.
More details: constructor of string from char* calls strlen-like function which looks like about this:
https://en.cppreference.com/w/cpp/string/byte/strlen
int strlen(char *begin){
int k = 0;
while (*begin != '\0'){
++k;
++begin;
}
return k;
}
If c-style char* string does not contain '\0' it cause accessing memory which doesn't belongs to you.
How to fix?
Answer (two options):
not use mixture of char* and std::string
char* output = new char[s.length()]; replace with char* output = new char[s.length() + 1]; memset(output, 0, s.length() + 1);
Also you must delete all memory which you newed. So add delete[] output; before return res;
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);
}
I'm doing an exercise in which I have to copy a c-style string into memory allocated on free store. I am required to do it without using subscripting and relying solely on pointer arithmetic. I wrote the following function-
char* str_dup(const char* s)
{
// count no. of elements
int i = 0;
const char* q = s;
while (*q) { ++i; ++q; }
//create an array +1 for terminating 0
char* scpy = new char[i + 1];
//copy elements to new array
while (*s)
{
*scpy = *s;
++s;
++scpy;
}
*scpy = 0;
return scpy;
}
The function is returning random characters. But if I change it into this-
char* str_dup(const char* s)
{
// count no. of elements
int i = 0;
const char* q = s;
while (*q) { ++i; ++q; }
//create an array +1 for terminating 0
char* scpyx = new char[i + 1];
char* scpy = scpyx;
//copy elements to new array
while (*s)
{
*scpy = *s;
++s;
++scpy;
}
*scpy = 0;
return scpyx;
}
it works. Can someone explain me why first code is not working and second is working?
The first code is not working since you return the final value of scpy, which at that point points at the terminating NUL character, and not the start of the string.
One solution is to do as you did, and save a copy of the original pointer to have something to return.
You should really use strlen() and memcpy(), they make this easier but perhaps they're off-limits to you.
How do I return a pointer to something in the middle of a char array?
// Returns a pointer to the first occurrence of the given character in the
// given string.
const char* strchr(const char* string, char charToFind) {
for (int i = 0; i < strlen(string); i++) {
if (string[i] == charToFind) {
return string[i]; // <== THIS IS WRONG, How do I fix this?
}
}
return '\0';
}
You can do it like this
return &string[i];
or like this:
return string+i;
It's the same thing.
Returning '\0', a char constant equal to zero, is logically incorrect: you should return 0 for a NULL pointer, or if you wish to return an empty C string, you could return a pointer to local static empty string, like this:
const char* strchr(const char* string, char charToFind) {
for (int i = 0; i < strlen(string); i++) {
...
}
// Not found - return an empty string:
static const char *empty = "";
return empty;
}
If you have a pointer to a string, adding N to it will return the pointer to the part of the same string, starting from the Nth character (for zero-based count).
Also, it's better to have a constant for the pointer to empty string.
static const char* EMPTY_STRING = '\0';
const char* strchr(const char* string, char charToFind) {
for (int i = 0; i < strlen(string); i++) {
if (string[i] == charToFind) {
return string+i;
}
}
return EMPTY_STRING;
}
As #dasblinkenlight mentioned, &string[i] or string + i both work for returning pointers to the middle of the string. And as #Oliver Matthews stated, you should be returning NULL if the character is not found. Perhaps beyond the scope of your original query, but for performance reasons, you may want to avoid calling strlen(), and just check for the end of string as you scan, like so:
const char* strchr(const char* string, char charToFind) {
for (int i = 0; string[i]; i++) { // Or you could say string[i] != '\0'
if (string[i] == charToFind) {
return string + i;
}
}
return NULL;
}
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;
}
}
}