I need help removing spaces and special characters from an char array.The problem I keep running into is that the erase function only works on string datatypes, if I'm not mistaken. The assignment calls for a char array not a string so I cant just convert it or have a string variable. I've tried looking it up but everything kind of just suggests to convert it to a string or start off as a string, which I can't do. I'm new to programming and pointers are a little weird to me so if the answer is obvious I am sorry.
#include "stdafx.h"
#include <iostream>
#include <stdio.h>
#include <string>
#include <stdlib.h>
#include <ctype.h>
using namespace std;
int main()
{
const int SIZE = 80;
char str[SIZE];
char* strPtr;
int strlength;
int j = 0;
int front = 0, back; int flag = 1;
strPtr = str;
cout << "This program checks for palidromes." << endl;
cout << "Please enter a phrase." << endl;
cout << endl;
cin.getline(str, SIZE);
//Get the length of string str
strlength = strlen(str);
//Convert all the characters in the string str to uppercase
for (int i = 0; i < strlength; i++)
{
if (!isupper(str[i]))
str[i] = toupper(str[i]);
}
//Remove all the special characters except letters a - z
for (int i = 0; i < strlength; i++)
if (!isalpha(str[i])||(!isalnum(str[i])))
{
str.erase(str[i]); // need help here. Not sure how to go about it.
}
//str[j] = '\0';
return 0;
}
char* tail = std::remove_if(str, str + strlength,
[](char c){ return !isalpha(c)||(!isalnum(c)); });
strlength = tail - str;
*tail = 0;
The other answer correctly points you to std::remove_if, but I suspect that you really want to understand how to implement the removal yourself, instead of dumping the problem on the C++ library. Also your own attempt at this converts all remaining characters to uppercase, which the other answer does not do.
This is actually simpler than you might think. The relevant bits are as follows:
char *p=str, *q=str;
while (*p)
{
if (isalpha(*p))
*q++=toupper(*p);
++p;
}
*q='\0';
For starters, there's no need to compute strlen() of this string. Simply iterating a pointer from the beginning of the string to the end, until it's pointing at the terminating '\0' is sufficient.
That would be the p pointer. p starts at the beginning of the string, and each iteration of the while loop increments it, with the while loop stopping at the \0.
Then, if p's character is alphabetic, it gets copied to the q pointer, converting it to uppercase, and advancing the q pointer too.
As such, only alphabetic characters get copied to q, everything else gets skipped.
q starts off pointing to the same buffer as p, the buffer with the string. If the string begins with alphabetic characters, the only thing that will happen is that each character gets copied on top of itself, with both p and q advancing together. As soon as p sees a non-alphabetic character, it continues to advance, but q is "left behind", and will continue to accumulate only any remaining alphabetic characters. And when everything is done, the '\0' gets written to q, terminating the new uppercase-only string.
The only real difficult part of this is understanding why everything must occur exactly in the sequence; i.e. the alphabetic character must be copied before p gets incremented, etc... Talk to your rubber duck, if you do not understand why, your rubber duck will explain it to you.
Related
I have a vector of words which holds some words.
std::vector<std::string> words;
These words are concatenated into an array of chars called features (after each word a null character (\0) is inserted into the array):
while (j < i - offset){
logger.message("j: " + toString(j) );
std::strcat(features,words.at(j).c_str());
std::strcat(features,"\0");
logger.message("std::strcat(features,words.at(j).c_str())");
j++;
}
After that I want to recover each of the words, but the following code prints all the words concatenated (it does not divides the words by the inserted null character \0).
char * features_ptr = features;
while(*features_ptr){
std::string Str = std::string(features_ptr);
logger.message( "palavra: " + Str);
features_ptr += strlen(features) + 1;
}
What should I do to get the strings word by word?
std::strcat will not add \0 delimiter because it operates on c-string and \0 is considered an empty string, so your features will be one string spliced together from all the words. If you treat it as array of chars then you can insert your \0. It is not clear what you are trying to achieve and whatever it is it doesn't look the right way of doing it, but for the sake of an exercise:
#include <iostream>
#include <vector>
#include <string>
#include <cstring>
int main()
{
char features[20];
std::vector<std::string> words = { "123","456","789" };
int i = 0;
for (size_t n = 0; n < words.size(); ++n)
{
for (size_t m = 0; m < words[n].size(); ++m)
features[i++] = words[n][m];
features[i++] = 0;
}
features[i] = 0; //<-- extra terminating null
char *features_ptr = features;
while (*features_ptr)
{
std::cout << features_ptr << std::endl;
features_ptr += std::strlen(features_ptr) + 1;
}
}
Demo: https://ideone.com/GoVlRl
123
456
789
Please note one important detail about this approach, additional features[i] = 0; after the for loop which adds second terminating null \0 at the end of your spliced string. This is essential if you want your while (*features_ptr) loop to stop at the end of the string.
I see a problem on this line:
features_ptr += strlen(features) + 1;
I suspect you mean
features_ptr += strlen(features_ptr) + 1;
As others have said, strcat probably also doesn't do what you want exactly, either.
C character array is considered as string till characters before NULL \0. If you use \0 inside a string, the string will be terminated at that NULL only. So "\0" is as good as an empty string.
Your problem is standard serialization and deserialization of array of strings. Instead of using \0 as delimiter, you can use some other character which is not present in the strings such as ~. However, if there is no such character available, you need to append more information in the serialized string to assist deserialization later. One such way is as shown here.
I need to return the last occurrence of a char in a const array of chars. So if I have a const array of chars that is ["helloe"] and the char index I need to return is "e", it will return the 5.
//s is a const array of chars that equals ["helloe"]
// c is the char "e"
// I need to return the index of the last occurrence of e which is 5
int reverse_find_character(const char s[], char c){
std::vector<int> no;
size_t bob = strlen(s);
size_t i;
for (i=bob;i>bob;i++){
if (s[i]==c){
no.push_back((int)i);
}
return *max_element(no.begin(),no.end());
}
std::vector<int> no;
// ...
no.push_back((int)i);
Why do you need a vector? You don't need a vector at all. You don't need to remember every occurrence of the searched character. You only need to find the last one.
for (i=bob;i>bob;i++){
This makes very little sense. Your intent seems to be to start scanning from the end of the string (bob is the string's length). Which would be a reasonable first start. But, if your intent is to start from the end of the string and work your way back to i=0, you expect i to be decremented, not incremented. Furthermore, the comparison i>bob again makes no sense. With the initial value of i being bob, the expression i>bob will evaluate to false, and this loop will never be executed.
Anyway, this whole thing is really much simpler than you think it is:
Start scanning the string, from start to finish.
Each time you see the character you are searching for, save its index in a variable.
Therefore, at the end of the scan, this variable will be the index of the last position of the character in your string, because you're scanning it from the beginning to the end.
In other words:
int reverse_find_character(const char s[], char c){
int pos=-1;
size_t i;
for (i=0; s[i]; ++i)
if (s[i] == c)
pos = i;
return pos;
}
P.S. You didn't ask about types, but it's more technically correct to use ssize_t instead of ints, in this context.
Another solution is to loop backward from the end and stop on the first occurrence of your char:
int reverse_find_character(const char s[], char c){
for (int i = strlen(s)-1; i>=0; --i)
if (s[i] == c)
return i;
return -1;
}
What about std::find with a reverse iterator. Then use std::distance to get the index.
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
const char str[] = "helloe";
auto it = std::find(crbegin(str), crend(str), 'e');
cout << std::distance(cbegin(str), (it + 1).base()) << '\n';
}
I tried making this small program that takes input and checks for vowels. If there are vowels then it appends them to a string and returns the size of the string.
My only problem is I can't get it to work using strings. What is the major difference over using character arrays? I can get the program to work using something like:
char entered[128];
//and then
char exceptions[11] = "aeiouAEIOU";
**Quick question about the above array. When I assign the buffer to 'exceptions' it has to be 11 or the compiler will error. Must I manually account for the NULL termination portion?
If I do something like:
if(cPtrI[i] == 'a'){
I get an error stating unknown operator '==' ??
I thought '==' was a check operator, and '=' was an assignment operator?
no match for 'operator==' in '*((+(((unsigned int)i) * 4u)) + cPtrI) == 'a''|
AND, if I do something like: (which I thought was correct, at first)
if(*cPtrI[i] == *cPtrJ[j]){
I get the same error as above, but referencing unknown operator *:
no match for 'operator*' in '**((+(((unsigned int)i) * 4u)) + cPtrI)'|
no match for 'operator*' in '**((+(((unsigned int)j) * 4u)) + cPtrJ)'|
I thought the * operator said, in effect, 'what is at' the address of where the pointer is pointing.
So, something like the above would read:
If(What is at index I of string 'a' EQUALS What is at index J of string 'exceptions'){
then ..
Any help with this one? I learned C a bit before C++, so perhaps this is where my confusing is coming from. It was my understanding the the above code would compare addresses of characters/variables they are pointing to. * indicates 'what is at' while just placing the pointer name would indicate the value the pointer is holding(which is an address of the variable being pointed to). Using &ptrName would be the address of the pointer itself, correct? Where have I gone wrong here?
#include <iostream>
#include <string>
int vowelCheck(std::string a);
int main()
{using namespace std;
string eString;
cout << "Enter a string: ";
cin >> eString;
cout << "There were " << vowelCheck(eString) << " vowels in that string.";
return 0;
}
int vowelCheck(std::string a)
{using namespace std;
string exceptions = "aeiouAEIOU";
string vowels;
string *cPtrI = &a;
string *cPtrJ = &exceptions;
for(int i = 0; i < a.size(); i++){
cout << i <<"i\n";
for(int j = 0; j < 10; j++){
cout << j << "j\n";
// cout << cPtrJ[j];
if(cPtrI[i] == cPtrJ[j]){ //if index of A equal index of J then
cout << "Added: " << cPtrJ[j];
vowels.append(cPtrJ[j]); // append that vowel to the string 'vowels'
break;
}
}
}
return vowels.size();
}
Using my debug tools listed above, the program will only increment through j = 8 then stops. Also, if I even enter an initial string something like AEIOU, it will string go through j = 8. So, it is not seeing the equivalent characters.
What am I doing wrong using strings?
Forget about pointers.
string *cPtrI = &a;
string *cPtrJ = &exceptions;
// ...
if(cPtrI[i] == cPtrJ[j]){ //if index of A equal index of J then
cPtrI[i] is the same as *(cPtrI + i), which would be indexing into an array of string.
That's why cPtrI[i] == 'a' doesn't compile. cPtrI[i] has type std::string& (remember, it's indexing into a non-existing array of std::string), and 'a' is a char. You can't compare the two.
std::string has an indexing operator of its own. Just don't use pointless pointers and it just works.
if(a[i] == exceptions[j]){
You appear to be counting the number of vowels in a string. Instead of writing out the for loops manually and building up a string, let's use count_if to do that. The plan is to create a function object that can detect if a character is a vowel and then use count_if to count the number of vowel characters in the string:
struct VowelFinder
{
bool operator()(char c)
{
std::string vowels = "aeiouAEIOU";
return vowels.find(c) != std::string::npos;
}
};
int vowelCheck(const std::string& a)
{
return std::count_if(a.begin(), a.end(), VowelFinder());
}
I've answered your C-related questions in comments.
As for your usage of std::string, you're actually trying to use std::string* for some reason. Don't do that. Just use the std::string; operator [] is overloaded for it to work as-is. At the moment you're treating cPtrI as a element of an array of strings.
For some weird reason, it keeps on creating uninitilized values when I pass in the length as 12, it creates an array of about 16 and stores the rest with crap that I don't want. Anyone know why this isn't working? It's for an assignment that's due tomorrow and this is my last problem... Any help would be appreciated thanks.
char * convertToUppercase (char* toUpSize, int length) {
std::cout << "ToUpsize: " << toUpSize << "\nLength: " << length << "\n";
char * upsized = new char[length];
for (int i = 0; toUpSize[i]; i++) {
upsized[i] = toupper(toUpSize[i]);
}
return upsized;
}
I think you either write i< length in the for loop, instead of toUpSize[i] as:
for (int i = 0; i < length; i++) {
upsized[i] = toupper(toUpSize[i]);
}
Or pass toUpSize as null-terminated string if you want to write toUpSize[i] in the for loop condition. If you do so, then you've to put \0 at the end of upsized after you exit from the loop, at index i for which toUpSize[i] is \0. And to accomplish this, you've te move the definition of i outside the for loop, so that you can use it after you exit from the loop.
Null-terminated string is what which has \0 character at the end of the string.
char x[] = {'N', 'a', 'w', 'a', 'z' };
char y[] = {'N', 'a', 'w', 'a', 'z', '\0' };
Here, x is not a null-terminated string, but y is a null-teminated string.
If the strings are defined as:
char z[] = "Nawaz";
const char *s = "Nawaz";
Here z and s are null-terminated string, because both of them are created out of "Nawaz" which is a null-terminated string. Note that sizeof("Nawaz") would return 6, not 5, precisely because there is an \0 at the end of the string.
You need to null-terminate the returned array if you want to print it like a string. Make sure that it ends with a null-terminator. Depending on how you calculate the length argument you may need to add extra space for it to the array. You may also want to make sure that the array that you pass in is null-terminated.
You need to add the termination char:
char * convertToUppercase (char* toUpSize, int length) {
std::cout << "ToUpsize: " << toUpSize << "\nLength: " << length << "\n";
char * upsized = new char[length];
int i;
for (i = 0; toUpSize[i]; i++) { // stops when you get toUpSize[i]==0
upsized[i] = toupper(toUpSize[i]);
}
upsized[i] = '\0'; //add termination
return upsized;
}
Your code assumes length to be the length of the allocated array, not the length of the string. strlen(toUpSize) counts the chars that are not '\0' from position 0 in toUpSize.
E.g.: strlen("abc\0def") -> 3
sizeof("abc\0def") -> 8!
Why are you even bothering with char pointers? This is C++, not C.
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
std::string to_upper_case(std::string str)
{
std::transform(str.begin(), str.end(), str.begin(), toupper);
return str;
}
int main()
{
std::cout << to_upper_case("hello world\n");
}
If you decide to stick to the C solution, reserve one more char for the NUL terminator and put it there:
char * upsized = new char[length + 1]; // note the +1
upsized[length] = 0;
I'm a beginner and i need to ask a question..
I wrote this small code that accepts a string from the user and prints it..very simple.
#include <iostream>
using namespace std;
int main()
{
int i;
char *p = new char[1];
for(i = 0 ; *(p+i) ; i++)
*(p+i) = getchar();
*(p+i) = 0;
for(i = 0 ; *(p+i) ; i++)
putchar(*(p+i));
return 0;
}
when i enter any string..like "stack overflow" for example..it will print "sta" and drop the rest of the string. I know it's an easy one to solve but since I've just started i can't understand what's wrong here . Thanks in advance .
There are several problems with this code. First, you have a buffer overflow, because char *p = new char[1] allocates only one character for storage. This is exceeded when i > 0. Next, your first loop will keep going until it reaches a point in unallocated memory (undefined behavior) that has a value of zero. This just happens to be after the third value in your case. You probably wanted something more like *(p+i-1) == 0 to give "the last character read meets some condition." Finally, you're allocating memory with new[] and not properly deallocating it with a matching delete[].
Consider using std::cin and std::string for much safer and correct code:
#include <iostream>
#include <string>
int main(int, char**) {
std::string s;
std::cout << "Enter a string: ";
std::cin >> s;
std::cout << s << std::endl;
}
Here is some code along your lines that seems to work. I'm sure there are better (and more C++-ish) ways to do this...
#include <iostream>
using namespace std;
#define MAXLEN 80
int main()
{
int i=0;
char c;
char *p = new char[MAXLEN + 1]; // 1 char will not be sufficient
do // Doing this with a for loop would be unreadable
{
c = getchar();
*(p+i) = c;
i++;
} while( c != '\n' && i < MAXLEN ); // Check for a newline. How do you enter the zero with a keyboard?
*(p+i) = 0; // Ensure that the last character is zero
for(i = 0 ; *(p+i) ; i++) putchar(*(p+i)); // This is OK but difficult to read
delete [] p; // Don't forget this
return 0;
}
The fact that your program does anything is just luck; what stops *(p+i) from being \0 to begin with? It's weird that you're using getchar() and putchar() in a C++ program, too. What's the story behind this program?
If you read into memory, be sure that you allocate enough. new char[1] creates an array of only one char, but you are reading more then that. A simple temporary fix would be to simply allocate more, say new char[255].
Other notes:
you never delete the memory you allocated: delete[] p;
you should check wether you read as much characters as your buffer can hold: for(..;.. && i<bufferSize;..)
the condition in the first loop always checks the next character, not what you just read
*(p+i) is equivalent to p[i], which is more readable
why read and write only one character at a time?
why not use iostreams (std::in, std::out) and std::string as you are using C++?
you only allocate space for one character but you try to put many chars in it.
Is this homework? if so please tag it as such. Are you allowed to use STL?
If so then use std::vector instead on new char[1];
EDIT:to do it without any fiddly bits or STL
const int MAX = 100;
char *p=new char[MAX];
for(i = 0 ; *(p+i) && i < MAX ; i++)
*(p+i) = getchar();
probably some out by ones - left as exercise