I have an assignment where I'm supposed to loop through a Character Array using a Recursive Function. I figured it would be easy since I would know the length of the array but then the prototype is give to me which I have to use:
void display(char str[])
I can't imagine how I'm supposed to loop through this recursively without knowing the length. Can anybody give me a nudge on this please?
void display(char str[])
{
if (*str) {
putchar(*str);
display(str+1);
}
}
C strings (assuming your character array is a C string) are assumed to be null terminated. So, you could, for instance, use a recursive function to compute the length and look for the null character for your base case to know you are done.
As mentioned by #abelenky and #Nathan, a character array is assumed to end with a "null" char (usually '\0').
Here's an example on how to find the number of characters
unsigned int strLen( const char[] str ) {
unsigned int len = 0;
while( str[len] ) {
len++;
}
return len;
}
Related
I'm trying to compile this code in order to reverse a string:
void reverse(char *str, int n)
{
if (n==0 || n==1) {
return; //acts as quit
} else {
char i = str[0]; //1st position of string
char j = str[n-1]; //Last position of string
char temp = str[i];
str[i] = str[j]; //Swap
str[j] = temp;
reverse(str[i+1],n-1); // <-- this line
}
}
#include <iostream>
int main()
{
char *word = "hello";
int n = sizeof word;
reverse(word, n);
std::cout << word << std::endl;
return 0;
}
The compiler reports an error where I call reverse() recursively:
invalid conversion from char to char* at reverse(str[i+1], n-1).
Why?
Any advice on other issues in my code is also welcome.
str[i+1] is a character, not a pointer to a character; hence the error message.
When you enter the function, str points to the character you're going to swap with the n:th character away from str.
What you need to do in the recursion is to increment the pointer so it points to the next character.
You also need to decrease n by two, because it should be a distance from str + 1, not from str.
(This is easy to get wrong; see the edit history of this answer for an example.)
You're also using the characters in the strings as indexes into the strings when swapping.
(If you had the input "ab", you would do char temp = str['a']; str['a'] = str['b']; str['b'] = temp;. This is obviously not correct.)
str[0] is not the position of the first character, it is the first character.
Use std::swap if you're allowed to, otherwise see below.
More issues: you shouldn't use sizeof word, as that is either 4 or 8 depending your target architecture - it's equivalent to sizeof(char*).
You should use strlen to find out how long a string is.
Further, you should get a warning for
char *word = "hello";
as that particular conversion is dangerous - "hello" is a const array and modifying it is undefined.
(It would be safe if you never modified the array, but you are, so it isn't.)
Copy it into a non-const array instead:
char word[] = "hello";
and increase the warning level of your compiler.
Here's a fixed version:
void reverse(char *str, int n)
{
if(n <= 1) // Play it safe even with negative n
{
return;
}
else
{
// You could replace this with std::swap(str[0], str[n-1])
char temp = str[0]; //1st character in the string
str[0] = str[n-1]; //Swap
str[n-1] = temp;
// n - 2 is one step closer to str + 1 than n is to str.
reverse(str + 1, n - 2);
}
}
int main()
{
char word[] = "hello";
// sizeof would actually work here, but it's fragile so I prefer strlen.
reverse(word, strlen(word));
std::cout << word << std::endl;
}
I'm going to dissect your code, as if you'd posted over on Code Review. You did ask for other observations, after all...
Firstly,
char *word = "hello";
Your compiler should warn you that pointing a char* at a literal string is undefined behaviour (if not, make sure that you have actually enabled a good set of warnings. Many compilers emit very few warnings by default, for historical reasons). You need to ensure that you have a writable string; for that you can use a char[]:
char word[] = "hello";
The next line
int n = sizeof word;
has now changed meaning, but is still wrong. In your original code, it was the size of a pointer to char, which is unlikely to be the same as the length of the word "hello". With the change to char[], it's now the size of an array of 6 characters, i.e. 6. The sixth character is the NUL that ends the string literal. Instead of the sizeof operator, you probably want to use the strlen() function.
Moving on to reverse():
You read characters from positions in the string, and then use those characters to index it. That's not what you want, and GCC warns against indexing using plain char as it may be signed or unsigned. You just want to index in one place, and your i and j are unnecessary.
Finally, the question you asked. str[i+1] is the character at position i+1, but your function wants a pointer to character, which is simply str+i+1. Or, since we worked out we don't want i in there, just str+1.
Note also that you'll need to subtract 2 from n, not 1, as it will be used as a count of characters from str+1. If you only subtract 1, you'll always be swapping with the last character, and you'll achieve a 'roll' rather than a 'reverse'.
Here's a working version:
void reverse(char *str, int n)
{
if (n < 2)
// end of recursion
return; //acts as quit
char temp = str[0];
str[0] = str[n-1]; //Swap
str[n-1] = temp;
reverse(str+1,n-2);
}
#include <iostream>
#include <cstring>
int main()
{
char word[] = "hello";
int n = std::strlen(word);
reverse(word, n);
std::cout << word << std::endl;
}
We can make further changes. For example, we could use std::swap to express the switching more clearly. And we could pass a pair of pointers instead of a pointer and a length:
#include <utility> // assuming C++11 - else <algorithm>
void reverse(char *str, char *end)
{
if (end <= str)
// end of recursion
return;
std::swap(*str, *end);
reverse(str+1, end-1);
}
and invoke it with reverse(word, word+n-1).
Finally (as I'm not going to mention std::reverse()), here's the idiomatic iterative version:
void reverse(char *str, char *end)
{
while (str < end)
std::swap(*str++, *end--);
}
use like this :
reverse(&str[i+1],n-1);
pass address of the (i+1)th position not value.
[PLEASE CHECK FINAL EDIT BELOW FOR UPDATE]
My C++ is a bit rusty (to say the least) and I'm having an issue trying to pass a char array into a function to manipulate the values. Example code below:
void myFunction(char* splitStrings,String stringToSetInLoop) {
char substringPtr[stringToSetInLoop.length()];
stringToSetInLoop.toCharArray(substringPtr, stringToSetInLoop.length());
for(int i = 0; i < 10; i++) {
splitStrings[i] = *substringPtr;
}
}
char *mySplitStrings[10];
myFunction(*mySplitStrings,String("Repeat Me"));
Serial.println(mySplitStrings[0]);
The code does not crash, but it outputs a blank line. I suspect that I need to initialize a 2 dimensional array outside the function to pass in so that memory space is allocated. I'm guessing that, although the substring pointer exists inside the function, the memory is destroyed, leaving the char* array mySplitStrings[0] pointing at nothing. Also, I think I need to pass in the reference to the array memory space, not as a pointer.
The ultimate goal here is to be able to pass a char array into a function, assign some values to it, then use those values back in the main code loop. If there's a better way to achieve this, then please let me know.
Thanks in advance. Please free me from my personal pointer/reference hell!
EDIT: Further note, this code is being run on an arduino, so the C++ is limited.
EDIT: When I try to pass in a reference to the char* pointer, I get this error, which I'm not sure how to change the function parameters to fix: error: cannot convert char* ()[10] to char for argument 1 to void myFunction(char*, String). Can anybody please take a stab at showing me a working example?
EDIT:
Thanks to the responses... I now have a working static library function that splits strings passed as a char* array. I know it's not pretty, but it does work. Thanks you to those who contributed. Code below:
void ExplodeString::explode(char* explodeResults[], String str, String delimiter) {
int delimiterPosition;
int explodeResultsCounter=0;
String subString;
do {
delimiterPosition = str.indexOf(delimiter);
if(delimiterPosition != -1) {
subString = str.substring(0,delimiterPosition);
char *subStringPtr[subString.length()+1];
subString.toCharArray(*subStringPtr, subString.length()+1);
explodeResults[explodeResultsCounter++] = strdup(*subStringPtr);
str = str.substring(delimiterPosition+1, str.length());
} else { // here after the last delimiter is found
if(str.length() > 0) {
subString = str;
char *subStringLastPtr[subString.length()+1];
subString.toCharArray(*subStringLastPtr, subString.length()+1);
explodeResults[explodeResultsCounter++] = strdup(*subStringLastPtr);
}
}
} while (delimiterPosition >=0);
}
Usage:
char* explodeResults[10];
ExplodeString::explode(explodeResults, String("cat:dog:chicken"), String(":"));
Serial.println(explodeResults[0]);
Serial.println(explodeResults[1]);
Serial.println(explodeResults[2]);
EDIT: Man, this is sooo much easier when you use the stdlib:
void ExplodeString::explode(std::vector<std::string> &explodeResults, std::string str, char delimiter) {
std::stringstream data(str);
std::string line;
while(std::getline(data,line,delimiter))
{
explodeResults.push_back(line);
}
}
Usage:
std::vector<std::string> commandsResult;
char delimiter[] = ",";
std::string _inputString = "my,string,to,parse";
ExplodeString::explode(commandsResult, _inputString, delimiter[0]);
How to pass an array of char*:
void myFunction(char* splitStrings[10], String stringToSetInLoop) {
// ...
char *mySplitStrings[10];
myFunction(mySplitStrings, String("Repeat Me"));
This will also work:
void myFunction(char* splitStrings[], String stringToSetInLoop) {
and this:
void myFunction(char** splitStrings, String stringToSetInLoop) {
Also, seems there is STL for avr platform - include it, C++ without STL is smth strange.
You are not allocating space for character arrays and just passing pointer of character array.
Instead of using char*splitStrings[10], you can use 2d char array with sufficient space to accomodate max length string. Assuming you max string length is less that 64 you can do something like this.
char splitString[10][64];
void myFunction(char**splitStrings,String stringToSetInLoop)
or
void myFunction(char splitString[][64], String stringToSetInLoop)
{
int len = stringToSetInLoop.length();
for(int i = 0; i<10; i++)
{
for(int j = 0; i<len; j++)
{
splitString[i][j] = stringToSetInLoop.charAt(j);
}
}
}
I'm pretty new with recursion. I need to write two functions. So far I wrote one, which entitles finding the length of a string. However, the second one, which is: finding the repeating character in an array is proving to be very difficult. I have scoured the web trying to find examples, I have been doing a lot of reading but nothing so far. So if you could point me in the right direction, I would really appreciate it.
Thank you
//length( ) -- this function is sent a null terminated array of characters.
//The function returns the length of the "string".
long slength (const char ntca[])
{
int length = 0;
if (ntca[length] == '\0'){
return 0;
}
else{
return slength(ntca+1)+1;
}
}
//countall( ) -- This function is sent a null terminated array of characters
//and a single character. The function returns the number of times the character
//appears in the array.
long countall (const char ntca[],char letter){
int position = 0;
int counter = 0;
long length = slength(ntca);
if (length == 0)
return 0;
else if (ntca[position]==letter)
return 1 + countall(ntca-1,letter);
else
return countall(ntca,letter);
}
You can try the below code:
long countall(const char *ptr, char letter)
{
if(!*ptr) return 0; //base case
return (*ptr == letter) + countall(ptr + 1, letter);
}
The base case of recursion is when function meets the end of the string. For an empty string and any letter the answer is 0.
If string is not empty, we add 1 to the result of recursive call on shorter string if and only if the current char matches letter.
char* a="HELLO WORLD";
IF ADDRESS of 'H' is 0x01 then the printf with %s prints to D but if the same code is written with manual printing routine
while(*a!=NULL) {printf("%c",n[a]);n++;}
this prints a few more characters..
but
printf("%s",a);
prints it perfectly.
while(*a++) printf("%c", *(a-1)); or
for(;*a++;)printf("%c", *(a-1));
although work but i dont want solutions but the process mechanisms..
so the question coming to my mind is
whether printf gets the length of the string from some register(or any memory unit)
or it performs character check.. then prints...
The way you're indexing into the character string is odd. It works for the string, but won't stop because you never change the value of *a. What your program does is try to get the a offset of n, so for the first 11 positions they are the same, but the loop doesn't terminate because *a will always be 'H'. What you'd want the terminating condition to be is n < strlen(a).
However, the more succinct way to write that program would be:
int main(int argc, char **argv) {
char *a = "HELLO WORLD";
while(*a) printf("%c", *a++);
return 0;
}
This works because a is an array of characters and as we're printing out each character (de-referencing the value stored at the position) we also increment to the next position. The string should terminate with a NULL reference, which will cause the loop to terminate sine *a == 0 at the NULL terminator.
did you mean or you have error:
int main() {
int n = 0;
char* a="HELLO WORLD";
while(a[n] != NULL) {printf("%c",a[n]);n++;}
}
explanation about what is wrong:
while(*a!=NULL) printf("%c",n[a]);n++;
a is not modified anywhere, so *a will not change it's value.
Although n[a] is perfectly valid construct in C I strongly recommend not to use it, because it is semantically incorrect. You access array by index, not index by array.
You increment index (n++) but check the pointer to array. You could possibly increment a inself like this: while(*a!=NULL) {printf("%c",*a);a++;}
The corect way to do this is:
#include <iostream>
using namespace std;
int main() {
char *a="HELLO WORLD";
int n = 0;
while(a[n]!=NULL){
cout<<a[n];
n++;
}
cout<<'\n';
return 0;
}
As far as I remember, by default when you created char* a it will be something as {HELLO WORLD\0} in memory ('\0' is how %s know the end of the your string is)..
Not sure if '\0' == null will yield true.. but I doubt it
I`m having problems converting a char array read from file to an int array. Maybe someone can help me. This is my code:
char vectorPatron[67];
int iPatrones[67];
archivo = fopen("1_0.txt", "r");
for(i=0;i<67;i++){
fscanf(archivo, "%c", &vectorPatron[i]);
printf("%c",vectorPatron[i]);
}
fclose(archivo);
for(i=0;i<67;i++){
iPatrones[i] = atoi(&vectorPatron[i]);
printf("%d",iPatrones[i]);
}
Despite using some C++ features, most of your code looks more like C. Might I recommend something more like:
struct to_int {
int operator()(char c) { return c - '0'; }
};
const int num = 67;
std::vector<char> patrons(num);
std::vector<int> patron_values(num);
std::ifstream archivo("1_0.txt");
archivo.read(&patrons[0], num);
std::cout.write(&patrons[0], num);
std::transform(patrons.begin(), patrons.end(), patron_values.begin(), to_int());
std::copy(patron_values.begin(), patron_values.end(),
std::ostream_iterator<int>(std::cout, "\n"));
That's because atoi receives a null-delimited string, while you are passing it a pointer to a single char (both are essentially char *, but the intent and use are different).
Replace the call to atoi with iPatrons[i] = vectorPatron[i] - '0';
Also, you can remove the vectorPatrons array, simply read into a single char in the first loop and then assign to the appropriate place in the iPatrons array.
I believe you cannot use the atoi function since it needs an string (array of chars terminated by the \0 character). Why dont you simply do:
for(i=0;i<67;i++){
iPatrones[i] = int(vectorPatron[i] - '0');
printf("%d",iPatrones[i]);
}
Note: i do not know how the source file looks like, so maybe the error is there. How exactly are those numbers stored in the file? Maybe you could use (if they are stored as number separated by space):
for(i=0;i<67;i++){
fscanf(archivo, "%d", &iPatron[i]);
}
Here is a very simple and reusable approach. This function converts a char into an int and returns the int. BAD_RETURN = 10 because every single character is from '0' to '9'. The source of this function is cplusplus.com.
int CharToInt(char ch)
{
return((ch >= '0' && ch <= '9') ? ch - '0' : BAD_RETURN);
}
This is my own function that works in VS2015 compiler. Define an int array and initialize it to 0s. Pass this int array along with the its char prototype array into following function. This function converts a char array into an int array using CharToInt function:
void copyCharArrToIntArr(char from[MAX], int to[MAX])
{
for (int i = 0; i < MAX; i++)
to[i] = CharToInt(from[i]);
}
This approach will work with vectors. Instead of MAX, use i < yourVector.size() for the for-loop condition.