nullptr not breaking loop over zero terminated string - c++

I tried using following code sample given in Tour of C++ which uses nullptr to break loop over zero terminated string. However, my sample program doesn't seem to stop in the loop.
Excerpt from the book:
first version of code from book:
```
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;
}
```
second simplified version
```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)
{
int count = 0;
while (p) {
if (*p==x)
++count;
++p;
}
return count;
}```
statement following code in the book:
The while-statement executes until its condition becomes false.
A test of a pointer (e.g., while (p)) is equivalent to comparing the pointer to the null pointer (e.g.,
while (p!=nullptr)).
My program using same structure:
char name[] = "ABCD";
char *p = name;
int count = 0;
int loopc = 0;
while (p)
{
loopc++;
if(*p == '\0')
cout << "zero found\n";
else
cout << *p << "\n";
//emergency stop
if (loopc == 12)
break;
p++;
}
expected:
Should stop after printing name.
actual:
A
B
C
D
zero found
zero found
zero found
zero found
zero found
zero found
zero found
zero found

Thanks for all the useful comments.
It seems the author had given wrong example in the earlier edition (1st) which was later corrected in second edition released in 2018.
Corrected version from new edition:
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!=0; ++p)
if (∗p==x)
++count;
return count;
}

the first version should return 0 when you pass it nullptr. In the for loop however you are passing once.
There is only one char* (consider using std::string btw) anyway...
Here is my quick fix, try to understand it:
int count_x(char* c_ptr, char c) {
if (c_ptr == nullptr) return 0;
int count = 0;
/* Note that I check if *c_ptr is '\0' that's the **value**
* pointed to by c_ptr
*/
for (; *c_ptr != '\0'; ++c_ptr) // '\0' is a nul character
if (*c_ptr == c) ++count;
return count;
}
int foo(const std::string& word, char letter) noexcept {
int count = 0;
for (const auto& c: word) { // for all const char ref in word
if (c == letter) ++count;
}
return count;
}
int main() {
int a = count_x("acbccc", 'c');
int b = foo("acbccc", 'c');
std::cout << a << '\n' << b;
}
Feel free to ask if you have any question.
Cheers.

Related

How to fix 'Heap has been corrupted 'error in c++?

When I run the program, I get exception "heap has been corrupted" after completion of the function
I have read that this exception may cause if you are using memory that has been freed, or when you are writing to index which is out of array index. But none of the cases applies here. I have read other answers of some problems but it didn't help much.
`char fileNametoExport[26]="d:\\FOlder1\\part1.ipt";
char WorkingFolderName[260] ="d:\\folder";
int start = rFind(fileNametoExport, '\\');
int finish = rFind(fileNametoExport, '.');
if (start == -1)
start = 0;
char partname[260];
strcpy(partname,substr(fileNametoExport, start, finish));
::AfxMessageBox((LPCTSTR)partname);
char xtfile[260];
char xmltxtfile[260];
strcpy(xtfile, strcat(WorkingFolderName, partname));
strcat(xtfile, "__Default.x_t");
strcpy(xmltxtfile, WorkingFolderName);
strcat(xmltxtfile,"_XT_SE_INV_Default_SOLID_0_Solid1_xt.xmt_txt");`
function rfind() to find occurence of char in char array-
int rFind(char* s, char c)
{
int sz = 0;
char *tmp = s;
while (*tmp != '\0')
{
sz++;
tmp++;
}
for (int i = sz - 1; i >= 0; i--)
{
if (*(s + i) == c)
return i;
}
return -1;
}
function substr() to get substring from position x to y (y exclusive)
char* substr(char* s, const int b, const int f)
{
char *str = new char[f - b];
int t = 0;
for (int i = b; i != f; i++)
{
str[t] = s[i];
t++;
}
str[t] = '\0';
return str;
}
P.S- While giving input I ensure that fileNametoExport always contains '.' and '\'.
Your program do not check lengths of input strings. You can receive a string longer than your buffer and program will fail.
If your program get fileNametoExport = "d:\\somefolder\\somefilewithoutdot" , finish will be -1 and program fail at strcpy(partname,substr(fileNametoExport, start, finish)); .
Program writes after buffer in char* substr(char* s, const int b, const int f) at line
str[t] = '\0';
because t at this point equal f-b , size of str buffer.
Function _ASSERTE( _CrtCheckMemory( ) ); from <crtdbg.h> very useful when searching for bugs like this. Put it around suspicious code and it fails after your bug. It works only in debug.

Function Bad pointer runtime error?

I am trying to implement function that searches for match between two C-style strings, as a part of an exercise from "Programming: Principles and Practice using C++".
However, I am getting a runtime unhandled exception:
Access violation reading location 0x008ff000.
that breaks at a bad pointer value (indicated in the code).
#include <iostream>
char* find (char* s, char* x) {
// variable that stores the first char of matching substring of s
char* match = nullptr;
// control variable indicating full match between x and substring of s
bool full_match = false;
if (s == nullptr || x == nullptr) return match;
size_t len_s = my_strlen(s);
size_t len_x = my_strlen(x);
// x must be shorter than s
if (len_s < len_x) return match;
// pointers to beginning and end of s and x, used for traversal loops
char *s_begin = s;
char *s_end = s + len_s;
char *x_begin = x;
char *x_end = x + len_x;
// traverse s
for (char* i = s_begin; s_begin != s_end; ++i) {
// test for match between s and the first char of x
if (*i == *x_begin) {
//-----------^
// Code breaks here. Hovering above shows: 0x008ff000 <Bad Ptr>
// assign s's matching char
match = i;
// if x's lenght is 1 return match
if (len_x == 1) return match;
// define new pointer to the next element of s
char *i_next = i + 1;
// traverse the rest of x
for (char* j = x_begin + 1; j != x_end; ++j) {
// if there is even one mismatch brake loop and continue traversing s
if (*i_next != *j) break;
// if the rest of x matches the rest of s, switch to full_match
else if (j == x_end - 1) full_match = true;
// increment x
++i_next;
}
// when x traversed and there is full_match, return the first matching char
if (full_match) return match;
}
}
// return nullptr to indicate no match
return nullptr;
}
//====================================================
int main () {
try {
char* source = "abcde\0";
char* target = "c\0";
char *match_found = find(source, target);
if(match_found) std::cout << *match_found << '\n';
} catch (std::exception &e) {
std::cerr << e.what() << std::endl;
getchar();
}
getchar();
}
Why is the pointer char* i not initialized to s_begin? What am I doing wrong?
Your loop condition is wrong. What you have is an infinite loop:
for (char* i = s_begin; s_begin != s_end; ++i)
Since s_begin will never equal s_end i ends up incrementing outside of the string. Change it to:
for (char* i = s_begin; i != s_end; ++i)

Using pointers to subsitute characters in C strings

This is not homework, but study for a midterm.
I cannot use any type of array indexing such as str[i] or *(str+i)
I have to take the c-string "EECS280ISAWESOME" and substitute the 'E' with the c-string "XY". I also have to allow for multiple length of the "XY" variable.
The following main is given:
int main () {
const char* S = "EECS280ISAWESOME";
const char* P = "XY";
char result[256];
subsituteChar(S,P,'E', result);
cout << result << endl;
}
My solution seems complex/bad practice/and ugly. I could do it better with the use of deferencing and adding *(R+1) but I dont think it's allowed.
void subsituteChar(const char* S, const char* P, char c, char* R) {
while(*S != '\0') {
if(*S == c) {
const char* PP = P;
while (*P != '\0') {
*R = *P;
R++;
P++;
}
P = PP;
} else {
*R = *S;
R++;
}
S++;
}
}
This works but I am left with XYXYCS280ISAWXYSOMXY2. I have no idea where the weird 2 has came from.
Since this is a study problem, here's a hint to get you started. Try initializing your result array. I did this:
char result[256];
for (int i = 0; i < 250; ++i)
result[i] = 'a';
result[250] = 0;
Now run your code again, and you'll see that you've got lots of 'a' characters at the end of your output, up to the point where you get to character 250. That is, you'll see:
"XYXYCS280ISAWXYSOMXYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
If you want to figure out the rest for yourself, STOP READING NOW.
The problem is that you're not explicitly null terminating your string.
Note that it's not a problem with your last character of S being replaced, but rather with your while loop's terminal condition. Since you aren't manually copying over the '\0' character from S, you're left hoping that the result array is full of '\0' characters, which C and C++ don't guarantee.
Simply adding the following line to the end of your substituteChar function will solve the problem:
*R = '\0';
Does this fit?
#include<stdio.h>
int main () {
const char* S = "EECS280ISAWESOME";
const char* P = "XY";
char result[256];
while(*S)
{
if(*S=='E')
printf("XY");
else
printf("%c", *S);
S++;
}
}
Your code is perfectly correct along with small error. There is a fact of string , everry
string should be terminate with null character. so just add the *R ='\0'; at the end of
while function and this algorithm works perfectely.

Recursive function for the recognition of the palindrome char arrays

I been assigned this exercise at college, but I don't know how to implement the recursion structure ( " ??? " in the code ). In the if-cycle I should match the first character in the array with the last and apply the recursion in order to reach the central character, but I don't know how to setup the code. The main function code compiles perfectly.
#include <iostream>
using namespace std;
const int DIM = 8;
bool is_palindrome (char* first, char* last)
{
if (first == last)
{
???
}
else
return false;
}
int main()
{
char a[DIM] = {'i','n','g','e','g','n','i','\0'};
char *first = &a[DIM] + 1;
char *last = &a[DIM] -1;
if (is_palindrome(first, last))
cout << " the char array is palindrome ";
else
cout << " the char array is not palindrome ";
return 0;
}
First of all, you will need to compare the values pointed to by the pointers, not the pointers themselves
if (*first == *last)
Second, you can advance the first and decrease the last to move one character:
// inside if
++first;
--last;
and call the function again with the new values of the pointers:
return is_palindrome(first, last);
You will also need to ensure that you do not go past the array when you actually get a palindrome, so add this check to the beginning of is_palindrome()
if (last < first) {
return true;
}
Also, in main() you need to initialize your pointers this way:
char* first = &a[0];
char* last = &[DIM-2];
The way you wrote it first already points past the array, while last points to the ending '\0', which will not match to any of the other characters.
using namespace std;
const int DIM = 8;
bool is_palindrome ( char* first , char* last )
{
if ( *first == '\0' )
{
return false;
}
else if ( first >= last )
{
return true;
}
else if ( *first == *last )
{
return is_palindrome(first + 1, last - 1);
}
else
{
return false;
}
}
int main ()
{
char a[DIM] = {'i','n','g','e','g','n','i','\0'};
char *first = a;
char *last = &a[DIM] - 2;
if ( is_palindrome ( first , last ) )
{
cout << " the char array is palindrome ";
}
else
{
cout << " the char array is not palindrome ";
}
return 0;
}

Find the first occurence of char c in char *s or return -1

For a homework assignment, I need to implement a function which takes a char *s and a char c and return the index of c if found, and -1 otherwise.
Here's my first try:
int IndexOf(const char *s, char c) {
for (int i = 0; *s != '\0'; ++i, ++s) {
if (*s == c) {
return i;
}
}
return -1;
}
Is that an okay implementation, or are there things to improve?
EDIT Sry, didn't mention that I only should use pointer-arithmetic/dereferencing, not something like s[i]. Besides, no use of the Standard Library is allowed.
Yes, it's fine, but you could increment only one variable:
int IndexOf(const char *s, char c) {
for (int i = 0; s[i] != '\0'; ++i) {
if (s[i] == c) {
return i;
}
}
return -1;
}
Won't make any serious difference though, mostly a matter of taste.
Looks fine to me, at least given the signature. Just to add to the "many slightly different ways to do it" roadshow:
int IndexOf(const char *s, const char c) {
for (const char *p = s; *p != 0; ++p) {
if (*p == c) return p - s;
}
return -1;
}
Slight issue - p-s isn't guaranteed to work if the result is sufficiently big, and certainly goes wrong here if the correct result is bigger than INT_MAX. To fix this:
size_t IndexOf(const char *s, const char c) {
for (size_t idx = 0; s[idx] != 0; ++idx) {
if (s[idx] == c) return idx;
}
return SIZE_MAX;
}
As sharptooth says, if for some didactic reason you're not supposed to use the s[i] syntax, then *(s+i) is the same.
Note the slightly subtle point that because the input is required to be nul-terminated, the first occurrence of c cannot be at index SIZE_MAX unless c is 0 (and even then we're talking about a rather unusual C implementation). So it's OK to use SIZE_MAX as a magic value.
All the size issues can be avoided by returning a pointer to the found character (or null) instead of an index (or -1):
char *findchr(const char *s, const char c) {
while (*s) {
if (*s == c) return (char *)s;
++s;
}
return 0;
}
Instead you get an issue with const-safety, the same as the issue that the standard function strchr has with const-safety, and that can be fixed by providing const and non-const overloads.
Here's a way to do it without keeping track of the index:
int IndexOf(const char *s, char c) {
const char *p = s;
while (*p != '\0') {
if (*p == c) {
return p - s;
}
++p;
}
return -1;
}
This is not necessarily better than your solution. Just demonstrating another way to use pointer arithmetic.
FWIW, I would define the function to return size_t rather than int. Also, for real-world usage (not homework), you would probably want to consider what the proper behavior should be if s is a NULL pointer.
Yours is perfectly fine, as far as it goes. You should also write a simple test program that tests for the first char, last char, and a missing char.
Piling on to the 'other ways to do it' group, here is one with no break, a single return, and showing off pointer arithmetic. But, beware: if I were grading your homework, I would grade yours higher than mine. Yours is clear and maintainable, mine needlessly uses ?: and pointer subtraction.
#include <stdio.h>
int IndexOf(const char *s, const char c)
{
const char * const p = s;
while(*s && *s != c) s++;
return (*s) ? s-p : -1;
}
#ifdef TEST
int main()
{
printf("hello, h: %d\n", IndexOf("hello", 'h'));
printf("hello, g: %d\n", IndexOf("hello", 'g'));
printf("hello, o: %d\n", IndexOf("hello", 'o'));
printf("hello, 0: %d\n", IndexOf("hello", 0));
}
#endif
The output of this program is:
hello, h: 0
hello, g: -1
hello, o: 4
hello, 0: -1
There's a typo (index instead of i), but otherwise it looks fine. I doubt you'd be able to do much better than this (both in terms of efficiency and code clarity.)
yes, you shoule return i;
not index.
I think it's just a typo.
Another variant, as an old school C programmer may write it:
int IndexOf(const char *s, char c) {
int i = 0;
while (s[i] && (s[i] != c)) ++i;
return (s[i] == c)?i:-1;
}
Benefices : short, only one variable, only one return point, not break (considered harmful by some people).
For clarity I would probably go for the one below:
int IndexOf(const char *s, char c) {
int result = -1;
for (int i = 0; s[i] != 0; ++i) {
if (s[i] == c) {
result = i;
break;
}
}
return result;
}
It uses a break, but has only one return point, and is still short.
You can also notice I used plain 0 instead of '\0', just to remind that char is a numeric type and that simple quotes are just a shorthand to convert letters to their values. Obviously comparing to 0 can also be replaced by ! in C.
EDIT:
If only pointer arithmetic is allowed, this does not change much... really s[i] is pointer arithmetic... but you can rewrite it *(s+i) if you prefer (or even i[s] if you like obfuscation)
int IndexOf(const char *s, char c) {
int result = -1;
for (int i = 0; *(s+i) != 0; ++i) {
if (*(s+i) == c) {
result = i;
break;
}
}
return result;
}
For a version that works for most cases on x86 systems, one can use:
int IndexOf(char *s, char sr)
{
uint_t *x = (uint_t*)s;
uint_t msk[] = { 0xff, 0xff00, 0xff0000, 0xff000000 };
uint_t f[4] = { (uint_t)sr, (uint_t)sr << 8, (uint_t)sr << 16, (uint_t)sr << 24 };
uint_t c[4], m;
for (;;) {
m = *x;
c[0] = m & msk[0]; if (!c[0]) break; if (c[0] == f[0]) return (char*)x - s;
c[1] = m & msk[1]; if (!c[1]) break; if (c[1] == f[1]) return (char*)x - s + 1;
c[2] = m & msk[2]; if (!c[2]) break; if (c[2] == f[2]) return (char*)x - s + 2;
c[3] = m & msk[3]; if (!c[3]) break; if (c[3] == f[3]) return (char*)x - s + 3;
x++;
}
return -1;
}
Limitations:
It breaks if the string is shorter than four bytes and its address is closer to the end of a MMU page than four bytes.
Also, the mask pattern is little endian, for big endian systems the order for the msk[] and f[] arrays has to be reversed.
In addition, if the hardware can't do misaligned multi-byte accesses (x86 can) then if the string doesn't start at an address that's a multiple of four it'll also fail.
All of these are solveable with more elaborate versions, if you wish...
Why would you ever want to do weird things like that - what's the purpose ?
One does so for optimization. A char-by-char check is simple to code and understand but optimal performance, at least for strings above a certain length, tends to require operations on larger blocks of data. Your standard library code will contain some such "funny" things for that reason. If you compare larger blocks in a single operation (and with e.g. SSE2 instructions, one can extend this to 16 bytes at a time) more work gets done in the same time.