I've been playing with pointers to better understand them and I came across something I think I should be able to do, but can't sort out how. The code below works fine - I can output "a", "dog", "socks", and "pants" - but what if I wanted to just output the 'o' from "socks"? How would I do that?
char *mars[4] = { "a", "dog", "sock", "pants" };
for ( int counter = 0; counter < 4; counter++ )
{
cout << mars[ counter ];
}
Please forgive me if the question is answered somewhere - there are 30+ pages of C++ pointer related question, and I spent about 90 minutes looking through them, as well as reading various (very informative) articles, before deciding to ask.
mars[i][j] will print the j'th character of the i'th string.
So mars[2][1] is 'o'.
As has been pointed out before, strings are arrays. In fact, this concept is carried on the the std::string-class (which, by the way, is the preferred way of representing strings in C++), which implements all the requirements of an STL-Sequence. Furthermore it implements the array-subscript operator. That means the expression:
mars[i][j]
would also work if mars was declared as
std::vector< std::string > mars;
which is much more the C++ way of handling this. I realize you are doing this to learn about pointers, but I just thought I'd add this for your information. Also, when learning about pointers in C++, you should also learn about iterators, as they are generalizations of pointers.
cout << mars[2][1] ;
mars is an array of char * so to get the individual char you have to index into the array of char
mars[counter] is of type char *, pointing to a zero-terminated string of characters. So you could:
for ( int counter = 0; counter < 4; counter++ )
{
char * str = mars[ counter ];
size_t len = strlen(str);
if (len >= 2)
cout << str[1];
}
Since others have suggested easy way, please also find one round-about way of doing it ;)
char *myChar = &mars[ 1 ][0];
int nPosOfCharToLocate = 1;
myChar = myChar + nPosOfCharToLocate;
cout <<*myChar<<endl;
Related
I am trying to make an own simple string implementation in C++. My implementation is not \0 delimited, but uses the first element in my character array (the data structure I have chosen to implement the string) as the length of the string.
In essence, I have this as my data structure: typedef char * arrayString; and I have got the following as the implementation of some primal string manipulating routines:
#include "stdafx.h"
#include <iostream>
#include "new_string.h"
// Our string implementation will store the
// length of the string in the first byte of
// the string.
int getLength(const arrayString &s1) {
return s1[0] - '0';
}
void append_str(arrayString &s, char c) {
int length = getLength(s); // get the length of our current string
length++; // account for the new character
arrayString newString = new char[length]; // create a new heap allocated string
newString[0] = length;
// fill the string with the old contents
for (int counter = 1; counter < length; counter++) {
newString[counter] = s[counter];
}
// append the new character
newString[length - 1] = c;
delete[] s; // prevent a memory leak
s = newString;
}
void display(const arrayString &s1) {
int max = getLength(s1);
for (int counter = 1; counter <= max; counter++) {
std::cout << s1[counter];
}
}
void appendTest() {
arrayString a = new char[5];
a[0] = '5'; a[1] = 'f'; a[2] = 'o'; a[3] = 't'; a[4] = 'i';
append_str(a, 's');
display(a);
}
My issue is with the implementation of my function getLength(). I have tried to debug my program inside Visual Studio, and all seems nice and well in the beginning.
The first time getLength() is called, inside the append_str() function, it returns the correct value for the string length (5). When it get's called inside the display(), my own custom string displaying function (to prevent a bug with std::cout), it reads the value (6) correctly, but returns -42? What's going on?
NOTES
Ignore my comments in the code. It's purely educational and it's just me trying to see what level of commenting improves the code and what level reduces its quality.
In get_length(), I had to do first_element - '0' because otherwise, the function would return the ascii value of the arithmetic value inside. For instance, for decimal 6, it returned 54.
This is an educational endeavour, so if you see anything else worth commenting on, or fixing, by all means, let me know.
Since you are getting the length as return s1[0] - '0'; in getLength() you should set then length as newString[0] = length + '0'; instead of newString[0] = length;
As a side why are you storing the size of the string in the array? why not have some sort of integer member that you store the size in. A couple of bytes really isn't going to hurt and now you have a string that can be more than 256 characters long.
You are accessing your array out of bounds at couple of places.
In append_str
for (int counter = 1; counter < length; counter++) {
newString[counter] = s[counter];
}
In the example you presented, the starting string is "5foti" -- without the terminating null character. The maximum valid index is 4. In the above function, length has already been set to 6 and you are accessing s[5].
This can be fixed by changing the conditional in the for statement to counter < length-1;
And in display.
int max = getLength(s1);
for (int counter = 1; counter <= max; counter++) {
std::cout << s1[counter];
}
Here again, you are accessing the array out of bounds by using counter <= max in the loop.
This can be fixed by changing the conditional in the for statement to counter < max;
Here are some improvements, that should also cover your question:
Instead of a typedef, define a class for your string. The class should have an int for the length and a char* for the string data itself.
Use operator overloads in your class "string" so you can append them with + etc.
The - '0' gives me pain. You subtract the ASCII value of 42 from the length, but you do not add it as a character. Also, the length can be 127 at maximum, because char goes from -128 to +127. See point #1.
append_str changes the pointer of your object. That's very bad practice!
Ok, thank you everyone for helping me out.
The problem appeared to be inside the appendTest() function, where I was storing in the first element of the array the character code for the value I wanted to have as a size (i.e storing '5' instead of just 5). It seems that I didn't edit previous code that I had correctly, and that's what caused me the issues.
As an aside to what many of you are asking, why am I not using classes or better design, it's because I want to implement a basic string structure having many constraints, such as no classes, etc. I basically want to use only arrays, and the most I am affording myself is to make them dynamically allocated, i.e resizable.
I am an Arduino noob attempting to select a random name from this array:
char ns[ ][3] = {"Carlos Alberto Castronovo","Tom Erbaugh","Caterina De Giacco","Di Puglia Pugliese Filomena","Manishwar Dhillon","Mel Richards","Connie Hvidtfeldt","Amy Namehere","Tim Beck","Sanil Sethi","Christophe Lavault","Steven Grimes","Jessica Serra","Mariateresa Petrucci","Patricia Anderson","Felma Roberto Cinco","Mai Ahmed","Tobe Levy","Indah Suspriati Wibawa","Dain Turgeon Orbe","Li Wang","Ed Clark","Elodie da Silva","Jason Garcia","Allan Litswa","Pietro Zubani","Cyril Jeanpierre","Kate Denali Princess","Maria Pilar Gl","Jefferson Ricarte","Adam Reed","László Lipták","Thalia Dbl","Maria Jose Calle Salas","William Alexander","Nicole Richardson","Andrea Hescher","Ismail Sholeh","Simone Spacci","Jason Jankow"};
But I receive this error, and I am not sure about different data types and how to approach fixing this array:
error: initializer-string for array of chars is too long
Is there something basic that I am missing?
It is exactly what it is informing: your character strings are way too long to fit in your char array, so your compiler is telling you that it will not proceed any further.
You can make it work by enhancing the size of your arrays like this:
char ns[ ][30] = //... ;
The 30 here is just to represent your biggest char string; it needs to have the size of your largest predefined char string + 1 (so that the null terminating character \0 can be added). For example, if your biggest string were "apple", your array would need to be of, at least, length 6.
You can iterate through these strings by doing this, for example:
int array_items = sizeof(ns) / sizeof(*ns); // this will gives you the amount of items stored in your array
int i;
int j;
for (i = 0; i < array_items; ++i) {
size_t strSize = strlen(ns[i]); // strSize now contains, if ns[i] contained the example of apple, 5
for (j = 0; j < strSize; ++j) {
printf("%c", ns[i][j]);
}
printf("\n");
}
That [3] means each string is limited to a maximum of 3 characters. And since one has to be the null terminator, it really means two. Your strings are a lot longer than that. Choose a number that's big enough to accommodate all of them.
ETA: #JLF: are you my long lost brother? :)
Let me ask my question by code:
char* apples = "apples";
std::string str("I like .....");
// need to copy apples to str to have "I like apples", without creating new objects
There is assign function but unfortunately it seems is not possible to provide std::string offset.
I do not want to allocate new object as this is low-latency and frequently part of code.
upd by mistake i've put 5 dots above but I meant 6 dots to fit "apples" perfectly :) Of course if string capacity is not enought some objects have to be created. In my question I assume that string capacity is enough.
You can use std::copy algorithm http://www.cplusplus.com/reference/algorithm/copy/
std::copy(apples, apples + sz, str.begin() + offset);
Why not use std::string::replace?
Even assign will copy the content of whatever you pass to it. You will not be able to do what you try to. A string holds a pointer to a continuous block of characters in the memory. You can not just glue arbitrary things to it.
The answer of using the std::copy() algorithm is the best one AFAIK. You could also use plain old C (you understand, it is not actually C, C style would be a better name) to achieve the same thing:
char* apples = "apples";
std::string str("I like .....");
char * ptr = apples;
while( *ptr != 0 ) {
str.push_back( *ptr );
++ptr;
}
As you can see, there is no temporary object created here, but... Does that mean there are no allocations in the process? Indeed they are.
A std::string is basically a vector of chars. The string has a capacity() method that returns how many extra chars can be appended without triggering another allocation (which can involve a reallocation, thus copying the whole vector). The best you can do in order to avoid allocations is to ensure that the string will have enough space for all characters to insert.
char* apples = "apples";
std::string str("I like .....");
str.reserve( str.length() + strlen( apples ) );
char * ptr = apples;
while( *ptr != 0 ) {
str.push_back( *ptr );
++ptr;
}
This way you can ensure that there will be one allocation only in the std::string: the one triggered with reserve().
Hope this helps.
char * apples = "apples";
string something = "I like ....";
for (int i = 0; i < something.length() - 1; i++)
{
if (something.find('.'))
something.pop_back();
}
something.resize(something.length() + 1);
for (int i = 0; i < strlen(apples); i++)
something.push_back(apples[i]);
cout << something <<endl;
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How do I use arrays in C++?
I have no idea how to push a char array.
For example if i have "HI.MY.NAME.IS" in a char array,
I would like to put one char in the middle and push the char's right to it.
So it would be something like "HI.MY.SLAME.IS" or something like that.
Any possible solutions?
Use string::insert.
std::string s("test");
s.insert(s.begin()+2, 'c');
There is no "automatic" push which relocates elements in an array. At the lowest levels, there is only read from an array element and write to an array element.
That means you need to copy each element after the insert "one index" down the array. Then you need to set the "inserted" value at its inserted index.
Library routines will do this for you without you noticing; however, you should be aware of the underlying mechanism. Otherwise, you might fall under the impression that inserting into arrays at arbitrary indexes is cheap (when it usually isn't).
//This allocates new memory that you receive responsibility for freeing after use.
char *push(char *charArray, char *charsToPush, int pushPos) {
char *thePushed = new char[strlen(charArray) + strlen(charsToPush) + 1];
memcpy(thePushed, charArray, pushPos);
memcpy(thePushed + pushPos, charsToPush, strlen(charsToPush));
memcpy(thePushed + pushPos + strlen(charsToPush), charArray + pushPos, strlen(charArray) - pushPos);
thePushed[strlen(charArray) + strlen(charsToPush)] = '\0';
return thePushed;
}
To do that you'd have to:
Create a new array that is large enough to hold the original and the new items. Arrays cannot be resized.
Copy all items from the old to the new array, leaving the places for the new characters open.
Insert the new characters.
This is quite complex. But C++ offers a simpler way - std::string:
#include <string>
#include <iostream>
int main() {
std::string text = "HI.MY.NAME.IS";
std::string new_text = text.substr(0, 6) + "SL" + text.substr(7, 6);
std::cout << new_text << std::endl;
}
This program prints HI.MY.SLAME.IS. Or, even better, use insert, as #rasmus suggests.
If you are limited to c-strings or require it to be replaced in-buffer, then you can do something like the below, but your buffer must be large enough to hold the modified string since it's pushing all characters down. That said, you'd be much better off using the std::string as the others suggest.
// ASSUMES buffer is large enough to store one more char
void insertAt(char* buffer, char insertMe, size_t at)
{
size_t len = strlen(buffer);
if (at <= len)
{
memcpy(buffer + at + 1, buffer + at, len - at + 1);
buffer[at] = insertMe;
}
}
char* string = (char*) malloc(14);
string = "HI.MY.NAME.IS";
realloc(string, 15);
for (int i = 14; i > 5; --i) {
string[i+1] = string[i];
}
string[5] = 'S';
string[6] = 'L';
Here you go...lol
I need to implement lastSeq function,which gets as argument string str and char chr
and returns the length of last sequence of repeated chr (the sequence can be of any length)
for example:
lastSeq("abbaabbbbacd",'a') should return 1
lastSeq("abbaabbbbacd",'b') should return 4
lastSeq("abbaabbbbacd",'t') should return 0
Is there C++ function which can solve it?
This appear to be homework, so I'm just going to give you direction so that you can find the answer by yourself.
First, how would you do it yourself, without a computer to give the correct result for your samples. From those manual run, how would you generalize then in simple steps so that you can solve the problem for all different inputs.
By this point you should have a rough algorithm to solve the problem. What do you know about storage of string in C++, and the method that are available from that class? Can some one them be used to solve some of the steps of your algorithm?
Try to write a program using those function, to compile it and to run it. Do you get the expected result? If not, can you try to print intermediate state (using std::cout << "Some value: " << variable << "\n";) to try to debug it.
Once you have done all of that, and if you are still having issues, update your question with your code, and we'll be able to give you more directed help.
int lastSeq(char *str, char chr)
{
int i = strlen(str);
int l = 0;
while(--i>=0)
if(*(str + i) == chr && ++l)
break;
while(--i>=0 && chr == *(str + i) && ++l);
return l;
}