Understanding code to reverse string - c++

I am struggling to understand the code below which is used to reverse a null-terminated string. I have written comments explaining the lines I am struggling to understand.
void reverse(char *str)
{
char *end = str;
char tmp;
if (str) // I don't understand what is happening within this if loop and how this is carried out for `str` which is not Boolean
{
while (*end) // I dont know what this means either
{
++end;
}
--end;
while (str < end)
{
tmp = *str
*str++ = *end //I am confused as to why this is not just *str = *end
*end-- = tmp; //Similarly, why is this not *end = tmp
}
}
}

if (str) means
Check if str a pointer to char is not NULL. Same as: if (str != NULL)
while (*end) check that the char pointed to by end is not the null-terminating character. Same as: while (*end != '\0')
*str++ = *end Assign the char pointed to by end to str and then advance str pointer by 1 char. *end-- advances end backwards by 1 char.
while (str < end) Compare the addresses as numbers (and not the values the pointers point to). This only makes sense if both pointers refer to different positions in the same memory block e.g. a c string in this case or any array. If str points to the 1st element of the string and end to the 2nd, then str < end will be true. The actuals chars in the 1st and 2nd positions will are not taken into account

*end = str; means the value of end pointer contains characters of string str
if (str) means check if str pointer isn't null ,so it's always true when str point to char.
while (*end) means check if end points to char , when pointer is null the condition is terminated , so when pointer reach the end of string end, while condition break and end pointer value contains the last char of string end.
*str++ = *end this statement can be break down to 2 statements to understand it :
first *str=*end; replace char value pointed by str with char pointed by end.
second *str++; move pointer to next character in string str after replacing.
*end-- = tmp; this statement can be break down to 2 statements to understand it :
first *end = tmp; replace char value pointed by end with tmp char.
second *end--; move pointer to previous char in string end after replacing.
I hope the idea is clear for you.

know that *end = str;
end = is the pointer here
They're checking the string if is not null if it is null ,if is should take the value of the char and assign to it
in your case the string is temp
i want you understand what char temp is doing and *end as pointer treat *end as a string meaning *end should not be null ,temp is character
while (*end)
++end;
it is telling that while end is not null, meaning the results should be a string ( e.g. a name like john)
--end it is telling you that the null should be clear
then it should go to another while
while (str < end) because the string is null
take char temp take to be a string
*str++ = *end then allow characters to make it a string or a name
or increement the character to make it a string
end-- = tmp // they are assign the string to that null string to have a vlue

Related

Pointer syntax and incrementation

#include <iostream>
#include <cstdlib>
using namespace std;
void reverse(char* str){
char *end = str;
char tmp;
if(str){
cout << "hello" << endl;
while(*end){
cout << end << endl;
++end;
}
--end;
while (str < end){
tmp = *str;
*str++ = *end;
*end-- = tmp;
}
}
}
int main(){
char str[] = "helloyouarefunny";
string input = str;
reverse(str);
for(int i = 0; i < input.length(); i++) {
cout << str[i];
}
}
Is if(str){} equivalent to if(str == NULL){}?
What does while(*end){} mean and what is it exactly doing? I think I have a general understanding that the while loop will continue to be executed as long as it does not "see" a '\0'. But I am not sure what is exactly going on with this line of code.
Given that if(str){} is an equivalent statement to if(str == NULL){}, what would you pass into a function to make str = NULL? For example, in my main(){}, I tried to do char str[] = NULL, thereby, attempting to pass a NULL so that it wouldn't go inside the code if(str == NULL){}. But I get an error saying I cannot make this declaration char str[] = NULL. So my question is why am I getting this error and what can I pass through the reverse() function in order to make the code inside of if(str){} not execute? I hope this question made sense.
And the code ++end is doing pointer arithmetic correct? So every time it is incremented, the address is moving to the address right next to it?
I'm a little confused while(str < end){}. What is the difference between just str and *str? I understand that cout << str << endl; has to do with overloading the operator << and therefore prints the entire string that is passed through the argument. But why, when I cout << *end << endl;, it only prints the character at that memory address? So my question is, what's the difference between the two? Is it just dereferencing when i do *str? I might actually be asking more than that question in this question. I hope I don't confuse you guys >_<.
Is if(str){} equivalent to if(str == NULL){}?
No, if(str){} is equivalent to if(str != NULL){}
What does while(*end){} mean and what is it exactly doing?
Since the type of of end is char*, while(*end){} is equivalent to while (*end != '\0'). The loop is executed for all the characters of the input string. When the end of the string is reached, the loop stops.
Given that if(str){} is an equivalent statement to if(str == NULL){}
That is not correct. I did not read rest of the paragraph since you start out with an incorrect statement.
And the code ++end is doing pointer arithmetic correct? So every time it is incremented, the address is moving to the address right next to it?
Sort of. The value of end is incremented. It points to the next object that it used to point to before the operation.
I'm a little confused while(str < end){}
In the previous while loop, end was incremented starting from str until it reached the end of the string. In this loop, end is decremented until it reaches the start of the string. When end reaches str, the conditional of the while statement evaluates to false and the loop breaks.
Update
Regarding
what would you pass into a function to make str = NULL?
You could simply call
reverse(NULL);
I tried to do char str[] = NULL;
str is an array of characters. It can be initialized using couple of ways:
// This is what you have done.
char str[] = "helloyouarefunny";
// Another, more tedious way:
char str[] = {'h','e','l','l','o','y','o','u','a','r','e','f','u','n','n','y', '\0'};
Notice the presence of an explicitly specified null character in the second method.
You cannot initialize a variable that is of type array of chars to to NULL. The language does not allow that. You can initialize a pointer to NULL but not an array.
char* s1 = NULL; // OK
reverse(s1); // Call the function
s1 = malloc(10); // Allocate memory for the pointer.
strcpy(s1, "test") // Put some content in the allocated memory
reverse(s1); // Call the function, this time with some content.
These are pretty standard C programming idioms.
No, in fact if (str) ... is equivalent to if (str != NULL) ...
C character strings are null terminated, meaning that "Hello" is represented in memory as the character array {'H', 'e', 'l', 'l', 'o', '\0'}. As with pointers, the 0 or NULL value is considered false in a logical expression. Thus while (*end) ... will execute the body of the while loop so long as end has not reached the null character.
N/A
Correct - this advances to the next character in the string, or to the null terminator.
This is the reverse algorithm. After the first loop, end points to one past the end of the string and str points to the beginning. Now we work these two pointers toward each other, swapping characters.
1/2) In C and C++, whatever is in the if or while is evaluated as a boolean. 0 is evaluated to false while any other value is evaluated to true. Given that NULL is equivalent to 0, if(str) and if(str != NULL) do the same things.
Likewise, while(*end) will only loop so long as the value end is pointing to does not evaluate to 0.
3) If you pass a char pointer to this function, it could be the null pointer (char *str = 0), so you're checking to make sure str is not null.
4) Yes, the pointer is then pointing to the next location in memory until eventually you find the null at the end of the string.
5) Perhaps your confusion is based around the fact that the code is missing parenthesis, the loop should look like:
while (str < end){
tmp = *str;
*(str++) = *end;
*(end--) = tmp;
}
So that the two pointers will continue to make there way towards eachother until crossing paths (at which point, str will no longer be less than end)

C++ Can't compare dereferenced char pointer to char

I have an input string, and I want to find how many spaces are there in the string.
Here's my code
// input string
std::string str = "abc d e f";
// convert string to cstring
char* cstr = new char[str.length()+1];
std::strcpy(cstr, str.c_str());
// iterate through the cstring and count how many spaces are there
int num_of_spaces = 0;
char* ptr = cstr;
while (ptr) {
if (*ptr == ' ') {
++num_of_spaces;
}
++ptr;
}
However, I got an error message on the if (*ptr == ' ') line that says: Thread 1: EXC_BAD_ACCESS (code = 1, address=0x100200000)
Isn't *ptr a char type value because ptr is a char* pointer and I dereferenced it to *ptr. If so, why the comparison is not valid?
You don't want while (ptr), you want while (*ptr), that is, while the thing ptr points to isn't a zero character which marks the end of a C-style string.

c++ char array null character while loop

I have a function that keeps on incrementing the char, so it will display the next char in the ascci code, but my problem is it never breaks the loop
char * myFunction (char* &text)
{
char *temp = (char *)malloc(strlen(text));
char *tmp = temp;
while(*tmp != '\0')
{
*tmp = *text++; //im incrementing the text
tmp +=1;
}
return temp;
}
char *text = "hello";
cout<<myFunction(text)<<endl;
while(tmp != '\0')
to be
while(*tmp != '\0')
tmp is the address of the start of the string which will never be '\0'
there are lots of problems in your code, I summarized them in comments below:
// Making your argument char*& allows you to modify text variable from
// calling function, I dont think this was your intention. If you just
// want to pass string to this function change its type to `const char*`.
// I dont think this return value you really want here, now you have char, but I
// suppose you want to return string, so it should be `char*` or `const
// char*`
char myFunction (char* &text)
{
// sizeof(text) will return 4bytes, which is size of pointer,
// you want strlen(text)+1 here to get length of string + 1
// char for zero (end of string)
char *temp = (char *)malloc(sizeof(text));
char *tmp = temp;
// You should dereference *tmp, but tmp is uninitialized here,
// I think you want to use *text here.
while(tmp != '\0')
{
*tmp = *text++; //im incrementing the text
// You are incrementing value pointed by tmp,
// if you want to increment tmp to next string
// element use tmp++;
*tmp +=1;
}
// Here assign zero to last element of text
// temp is char* and your return value is char, this is wrong,
// you should change return value of myFunction to char*. Also
// remember to call free() on returned string once its no
// longer needed - otherwise you will introduce memory leaks
return temp;
}
// This should be `const char *text = "hello";` In c++ string
// literals are of type `const char*`
char *text = "hello";
cout<<myFunction(text)<<endl;

Initializing a pointer to point to a character in a string using the pointer pointing to the string

int isPurePalindrome(const char *sentence){
int i;
if (sentence="")
return 0;
char *begin; char *end; i=strlen(sentence);//i is now the length of sentence string
*begin= &sentence(0);
*end=&sentence[i-1];
I'm using dev c++. Im trying to initialize pointer "begin" to point to the first character in the string "sentence", but it keeps giving me an error that "assignment makes integer from pointer without a cast."
"*sentence" points to the string entered by the user in the main. ispalindrome is a function im writing. its suppose to return a 0 if the sentence entered in main is a NULL.
There are a few issues with your code:
if (sentence="") return 0;
should be
if (strcmp(sentence,"")==0) return 0;
char *begin; char *end;
should be
const char *begin; const char *end;
*begin= &sentence(0);
should be
begin = &sentence[0];
*end=&sentence[i-1];
should be
end = &sentence[i-1];
There are a bunch of problems in your code, but the one causing that error message is that you're dereferencing when you don't need to be. You want:
begin = &sentence[0];
end = &sentence[i-1];
begin = &sentence[0];
end = &sentence[i - 1];
This will solve your problem..
You should write [] insted of () in
*begin= &sentence(0);
you should caste sentence to (char*) before assigning it to begin and end.
*begin = ((char*)sentence)[0];
*end = ((char*)sentence)[i -1];

Access Violation With Pointers? - C++

I've written a simple string tokenizing program using pointers for a recent school project. However, I'm having trouble with my StringTokenizer::Next() method, which, when called, is supposed to return a pointer to the first letter of the next word in the char array. I get no compile-time errors, but I get a runtime error which states:
Unhandled exception at 0x012c240f in Project 5.exe: 0xC0000005: Access violation reading location 0x002b0000.
The program currently tokenizes the char array, but then stops and this error pops up. I have a feeling it has to do with the NULL checking I'm doing in my Next() method.
So how can I fix this?
Also, if you notice anything I could do more efficiently or with better practice, please let me know.
Thanks!!
StringTokenizer.h:
#pragma once
class StringTokenizer
{
public:
StringTokenizer(void);
StringTokenizer(char* const, char);
char* Next(void);
~StringTokenizer(void);
private:
char* pStart;
char* pNextWord;
char delim;
};
StringTokenizer.cpp:
#include "stringtokenizer.h"
#include <iostream>
using namespace std;
StringTokenizer::StringTokenizer(void)
{
pStart = NULL;
pNextWord = NULL;
delim = 'n';
}
StringTokenizer::StringTokenizer(char* const pArray, char d)
{
pStart = pArray;
delim = d;
}
char* StringTokenizer::Next(void)
{
pNextWord = pStart;
if (pStart == NULL) { return NULL; }
while (*pStart != delim) // access violation error here
{
pStart++;
}
if (pStart == NULL) { return NULL; }
*pStart = '\0'; // sometimes the access violation error occurs here
pStart++;
return pNextWord;
}
StringTokenizer::~StringTokenizer(void)
{
delete pStart;
delete pNextWord;
}
Main.cpp:
// The PrintHeader function prints out my
// student info in header form
// Parameters - none
// Pre-conditions - none
// Post-conditions - none
// Returns - void
void PrintHeader();
int main ( )
{
const int CHAR_ARRAY_CAPACITY = 128;
const int CHAR_ARRAY_CAPCITY_MINUS_ONE = 127;
// create a place to hold the user's input
// and a char pointer to use with the next( ) function
char words[CHAR_ARRAY_CAPACITY];
char* nextWord;
PrintHeader();
cout << "\nString Tokenizer Project";
cout << "\nyour name\n\n";
cout << "Enter in a short string of words:";
cin.getline ( words, CHAR_ARRAY_CAPCITY_MINUS_ONE );
// create a tokenizer object, pass in the char array
// and a space character for the delimiter
StringTokenizer tk( words, ' ' );
// this loop will display the tokens
while ( ( nextWord = tk.Next ( ) ) != NULL )
{
cout << nextWord << endl;
}
system("PAUSE");
return 0;
}
EDIT:
Okay, I've got the program working fine now, as long as the delimiter is a space. But if I pass it a `/' as a delim, it comes up with the access violation error again. Any ideas?
Function that works with spaces:
char* StringTokenizer::Next(void)
{
pNextWord = pStart;
if (*pStart == '\0') { return NULL; }
while (*pStart != delim)
{
pStart++;
}
if (*pStart = '\0') { return NULL; }
*pStart = '\0';
pStart++;
return pNextWord;
}
An access violation (or "segmentation fault" on some OSes) means you've attempted to read or write to a position in memory that you never allocated.
Consider the while loop in Next():
while (*pStart != delim) // access violation error here
{
pStart++;
}
Let's say the string is "blah\0". Note that I've included the terminating null. Now, ask yourself: how does that loop know to stop when it reaches the end of the string?
More importantly: what happens with *pStart if the loop fails to stop at the end of the string?
This answer is provided based on the edited question and various comments/observations in other answers...
First, what are the possible states for pStart when Next() is called?
pStart is NULL (default constructor or otherwise set to NULL)
*pStart is '\0' (empty string at end of string)
*pStart is delim (empty string at an adjacent delimiter)
*pStart is anything else (non-empty-string token)
At this point we only need to worry about the first option. Therefore, I would use the original "if" check here:
if (pStart == NULL) { return NULL; }
Why don't we need to worry about cases 2 or 3 yet? You probably want to treat adjacent delimiters as having an empty-string token between them, including at the start and end of the string. (If not, adjust to taste.) The while loop will handle that for us, provided you also add the '\0' check (needed regardless):
while (*pStart != delim && *pStart != '\0')
After the while loop is where you need to be careful. What are the possible states now?
*pStart is '\0' (token ends at end of string)
*pStart is delim (token ends at next delimiter)
Note that pStart itself cannot be NULL here.
You need to return pNextWord (current token) for both of these conditions so you don't drop the last token (i.e., when *pStart is '\0'). The code handles case 2 correctly but not case 1 (original code dangerously incremented pStart past '\0', the new code returned NULL). In addition, it is important to reset pStart for case 1 correctly, such that the next call to Next() returns NULL. I'll leave the exact code as an exercise to reader, since it is homework after all ;)
It's a good exercise to outline the possible states of data throughout a function in order to determine the correct action for each state, similar to formally defining base cases vs. recursive cases for recursive functions.
Finally, I noticed you have delete calls on both pStart and pNextWord in your destructor. First, to delete arrays, you need to use delete [] ptr; (i.e., array delete). Second, you wouldn't delete both pStart and pNextWord because pNextWord points into the pStart array. Third, by the end, pStart no longer points to the start of the memory, so you would need a separate member to store the original start for the delete [] call. Lastly, these arrays are allocated on the stack and not the heap (i.e., using char var[], not char* var = new char[]), and therefore they shouldn't be deleted. Therefore, you should simply use an empty destructor.
Another useful tip is to count the number of new and delete calls; there should be the same number of each. In this case, you have zero new calls, and two delete calls, indicating a serious issue. If it was the opposite, it would indicate a memory leak.
Inside ::Next you need to check for the delim character, but you also need to check for the end of the buffer, (which I'm guessing is indicated by a \0).
while (*pStart != '\0' && *pStart != delim) // access violation error here
{
pStart++;
}
And I think that these tests in ::Next
if (pStart == NULL) { return NULL; }
Should be this instead.
if (*pStart == '\0') { return NULL; }
That is, you should be checking for a Nul character, not a null pointer. Its not clear whether you intend for these tests to detect an uninitialized pStart pointer, or the end of the buffer.
An access violation usually means a bad pointer.
In this case, the most likely cause is running out of string before you find your delimiter.