Pointer syntax and incrementation - c++

#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)

Related

Aren't pointers supposed to point to nullptr when an array ends?

Why does this code not work?, I used the function from "A Tour of C++" and it tells me that pointers point to nullptr when an array ends briefly explained. I tried to implement it and it doesn't show anything. Thanks in advance.
#include <iostream>
int count_x(char* p, char x)
{
int count = 0;
while (p)
{
if (*p == x){++count;}
p++;
}
return count;
}
int main()
{
char my_string[] {"hello world"};
char* my_string_ptr {my_string};
std::cout << "There are " << count_x(my_string_ptr,'a') << " a in the string\n";
return 0;
}```
No, pointer at the end of an array are not null. You probably want:
while (*p)
which is the same as
while (*p != '\0')
and
while (*p != 0)
which are testing for the null character.
p stores an address value in the computer memory which is deferenced by astricks (*) like *p.
In your code,
p++;
is incrementing the current address to which the p is pointing currently. When you reach the end of the string (at the last null character), p will be the address of the null character not the null itself, so
while(p)
will be true and following p++ will increment it to next memory location (which technically does not belong to the allocated string), and hence p will return non-zero address this while loop will keep on running and you will get a segmentation fault.
As the jeffrey has mentioned in his answer too, use *p to test the while condition so when p reaches the null, it can derefer it.
Your original code crashed (or caused segmentation fault). The reason is that in the while loop, you did not correctly specify the condition to exit this while loop. Therefore, the while loop will continue to go past the end of the string, which causes segmentation fault (i.e, your app will crash).
One correct way to exit the while loop is to compare each character of the string to see if that character equals the end of string character that is '\0'.
When you encounter this end of string character that is '\0', you should exit the while loop.
I have fixed one line of your code, and your function is now working fine as shown below:
int count_x(char* p, char x)
{
int count = 0;
while (*p != '\0') // I fixed your code here
{
if (*p == x){++count;}
p++;
}
return count;
}
Again, please note that the code above runs well, and produces the correct result as I have verified it. Please let me know if you run into any issue. Cheers.

Is nullptr used to terminate C-style strings?

I am confused by the use of nullptr in an example from A Tour of C++:  
int count_x(char* p, char x)
// count the number of occurrences of x in p[]
// p is assumed to point to a zero-terminated array of char (or to nothing)
{
if (p==nullptr) return 0;
int count = 0;
for (; p!=nullptr; ++p)
if (*p==x) ++count;
return count;
}
// The definition of count_x() assumes that the char* is a C-style string,
// that is, that the pointer points to a zero-terminated array of char.
I understand that count_x should terminate if p is unassigned, and the for loop should terminate when it reaches the end of the C-style string referenced by p.
However, when I build a main function to use count_x(), it never seems to terminate correctly:
int main () {
char teststring[] = {'b', 'l', 'a', 'h', '\0'};
cout << "teststring is: " << teststring << endl;
cout << "Number of b's is: " << count_x(teststring, 'b') << endl;
return 0;
}
Executing this prints a lot of garbage, and then exits with a segmentation fault. If I replace the for (; p!=nullptr; ++p) in count_x with for (; *p!='\0'; ++p), it executes properly. I guess this means that the string is not terminated correctly. If so, how do I terminate a C-style string so that nullptr can be used here?
Edit: there's been a discussion in the comments that's clarified this situation. I'm using the first print of the book from September 2013, where the above is printed in error. The third print of the book from January 2015 (linked in the comments) has the corrected example which uses for (; *p!=0; ++p) instead of for (; p!=nullptr; ++p). This correction is also documented in the errata for the book. Thanks!
Edit2: Sorry guys, this was apparently already asked on SO earlier here: Buggy code in "A Tour of C++" or non-compliant compiler?
No, a NULL pointer is not used to terminate strings. The NUL character is used. They are different things, but if you assign either of them to an integer in C, the result is always the same: zero (0).
A NUL character is represented in C as '\0' and takes up one char of storage. A NULL pointer is represented in C as 0, and takes up the same storage as void *. For example, on a 64-bit machine, a void * is 8 bytes while '\0' is one byte.
I.e., nullptr is not the same thing as '\0'. And the character is the null character, called NUL, but it is not supposed to be called a NULL byte or a NULL character.

Understanding code to reverse string

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

Counting Bytes Of Char S

I have a homework, It is:
Write the code of function below, this function should count number of bytes inside of s till it is not '\0'.
The function:
unsigned len(const char* s);
Really I do not know what this homework mean, can anyone write this homework's code please?
Further more can anyone please explain what does "Const char* s" mean? If you can explain with some examples it would be perfect.
Here is a code which I'm trying to do:
unsigned len(const char* s)
{
int count=0;; int i=0;
while (*(s+i)!=0)
{
count++;
i++;
}
return count;
}
But in the main function I do not know what should I write, BTW I have written this:
const char k='m';
const char* s=&k;
cout << len(s) << endl;
The result always is 4! really I do not know what should I do for this question, if I can store only one character in const char, so the result should be the same always. What this question is looking for exactly?
The homework means you should write a function that behaves like this:
int main() {
char s[] = {'a','b','c','\0'};
unsigned s_length = len(s);
// s_length will be equal to 3 ('a','b','c', not counting '\0')
}
I think it's unlikely that anyone will do you homework for you here.
Presumably your class has covered function parameters, pointers, and arrays if you're being asked to do this. So I guess you're asking about const. const char* s means that s points to a const char, which means you're not allowed to modify the char. That is, the following is illegal:
unsigned len(const char *s) {
*s = 'a'; // error, modifying a const char.
}
Here are the basic things you need to know about pointers to write the function. First, in this case the pointer is pointing at an element in an array. That is:
char A[] = {'a','b','c','\0'};
char const *s = &A[0]; // s = the address of A[0];
The pointer points to, or references, a char. To get that char you dereference the pointer:
char c = *s;
// c is now equal to A[0]
Because s points at an element of an array, you can add to and subtract from the pointer to access other elements of the array:
const char *t = s+1; // t points to the element after the one s points to.
char d = *t; // d equals A[1] (because s points to A[0])
You can also use the array index operator:
char c = s[0]; // c == A[0]
c = s[1]; // c == A[1]
c = s[2]; // c == A[2]
What would you used to look at each element of the array sequentially, with an increasing index?
Your proposed solution looks like it should work correctly. The reason you're getting a result of 4 is just coincidence. You could be getting any results at all. The problem with the way you're calling the function:
const char k='m';
const char* s=&k;
cout << len(s) << endl;
is that there's no '\0' guaranteed to be at the end. You need to make an array where one of the elements is 0:
const char k[] = { 1,2,3,0};
const char* s = &k[0];
cout << len(s) << '\n'; // prints 3
char m[] = { 'a', 'b', 'c', 'd', '\0', 'e', 'f'};
cout << len(m) << '\n'; // prints 4
char const *j = "Hello"; // automatically inserts a '\0' at the end
cout << len(j) << '\n'; // prints 5
In C (and by extension C++), strings can be represented as a sequence of characters terminated by a null character. So, the string "abc" would be represented as
'a', 'b', 'c', '\0'
This means, you can get the length of a C string by counting each character until you encounter a null. So if you have a null terminated const char* string, you can find out the length of that string by looping over the string and incrementing a counter variable until you find the '\0' character.
it means you have a string like hello world Every string terminates with a \0. That means it looks like this: hello world\0
Now step over the char array (char* s) until you find \0.
Update:
\0 is in fact only one single character of value 0x00. \ is used to tell visualize that this is meant instead of the number 0 in a string.
Example:
0abc\0 -> string starting with number 0 and is terminated with 0x0.
EDIT
char * indicates the type of the variable s. It is a pointer to a character array. const means that this character array is readonly and can't be changed.
Do you actually mean "count the characters till you find a '\0'"?
If so, you could implement it like this:
for each character
if it is not 0
increment x (where x is variable holding number of characters found)
otherwise
stop looking
return x
I am not going to write your homework as well :P, but let me give you some hint: it's called "pointer arithmetic". So, a pointer is a thing exactly just as it names says: a pointer to a memory "cell". As you know all variables in the memory are stored in "cells", that you can refer by an address. A C string is stored in continuous cells in the memory, so for example "abc" would look like something like (the '\0' is added by the compiler when you define a string literal with quotes):
+----+----+----+----+
|'a' |'b' |'c' |'\0'|
+----+----+----+----+
^
s
and you also get the address of the first char. Now, to get the address of 'b', you can simple add one to s like this: (s + 1). To get what is actually in the cell where s points to, you should use the * operator:
*s = 'a' or *(s + 1) = 'b'. This is called pointer arithmetic.
Note: in this case adding one to the pointer shifts to the next cell, because char is one byte long. If you define a pointer to bigger structure (long int for example of 4 bytes) adding one will move to the to the position in the memory where your next structure would begin (in case of long int it will move +4 bytes).
Now that should be enough help to finish your hw.
OK , I have found my answer, just check if I'm true:
#include <iostream>
using namespace std;
unsigned len(const char*);
int main()
{
const char* s = "Hello";
cout << len(s) << endl;
return 0;
}
unsigned len(const char* s)
{
int count=0;; int i=0;
while (*(s+i)!=0)
{
count++;
i++;
}
return count;
}
So it is showing that I have set "Hello" into const char* s; So for const char* variables I should use strings like "Hello" with the sign ("). Is that True?

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.