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
Related
Could someone explain to me, why there are 4 additional slots in char tab[], when I asked only for 3? How to get rid of them? I'm coding in Visual Studio 2017. Edit: the first program was very basic and didn't show what I intended. So, there is an extended one.
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int i, n;
vector<char> input;
char chp;
cout << "Enter a expression" << endl;
while (1)
{
cin.get(chp);
if (chp == '\n') break;
input.push_back(chp);
}
n = input.size();
char* tab = new char[n] {};
for (i = 0; i < n; i++)
{
tab[i] = input[i];
}
int l = strlen(tab);
for (int i = 0; i < l; i++)
{
cout << "tab[" << i << "] is " << tab[i] << endl;
}
cin.get();
}
Result in console window is similar, when I enter "3+3"
tab[0] is 3
tab[1] is +
tab[2] is 3
tab[3] is ř
tab[4] is ř
tab[5] is ř
tab[6] is ř
This isn't still the full program (full program is a calculator, that calculates any math expression, and is much longer). I wrote that in C long time ago, and in C dynamic arrays are not such a problem.
Also, what about multidimensional arrays? Can string be a solution also for them?
Could someone explain to me, why there are 4 additional slots in char tab[], when I asked only for 3?
There aren't. The array has only 3 elements.
The problem is that your array elements have indeterminate values. As a consequence of passing a pointer to array of indeterminate values into strlen, the behaviour of your program is undefined.
Solution: Initialise your array. Furthermore, initialise it so that it contains a null terminator, as required by strlen:
char* tab = new char[3]{'a', 'b', '\0'};
As alternative to null termination, don't use strlen to get the length. You already know that the array contains 3 elements. But the values must still be initialised before you insert them into the output stream.
P.S. Don't forget to delete memory that you allocate:
delete[] tab;
char* name[4];
int j=0;
while(cin.getline(name[j],80))//input given:you(ent)me(ent)he(ent)she
cout<<name[j++];
this code is reading only one string upto one newline.should'nt it read all 4 strings and print them ?and is this a good way to input string using getline?
Problem: You are not allocating the memory properly. You are declaring an array of pointers not an array of c style strings.
Possible Solutions: You need to read about pointers and memory allocation first. You can either allocate memory first to each of the four pointers that you declared name[0], name[1], name[2], and name[3] using the following code:
char* name[4];
for (int i = 0; i < 4; i++)
{
name[i] = new char[80];
}
OR you can use a 2D array for which the code is posted below:
char name[4][80];
int j=0;
while(j<4 && cin.getline(name[j],80))
{
cout<<name[j++];
}
I made a bit of correction. And it works on my computer.
char* name[4];
for (int i = 0; i < 4; i++)
name[i] = new char[80];
int j = 0;
while (j < 4)
{
cin.getline(name[j], 80); //input given:you(ent)me(ent)he(ent)she
cout << name[j++] << endl;
}
You need to read some more about pointers, arrays and memory management in C++ i guess. You try to operate on C array of strings, but you didn't initialize it properly. You need to allocate memory before you use such pointers. Currently your program results in UB so you are actually really lucky that it did anything same at all.
Another issue is that, when you reach the end of your input, when j=4, you will still attempt to perform cin(getline(name[j], 80) but you are passing the name[4] as a parameter, which may be a cause of another UB, even if you allocate the memory correctly beforehand.
Other then that you are writing in C++, so use C++ string and vector instead of C arrays.
This is easily done with strings and std::getline:
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<string> names;
string name;
while(getline(cin, name)){
names.push_back(name);
cout<<name<<endl;
}
return 0;
}
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.
The program itself works correctly, does what it's supposed to (seperate the words in a sentence and print them out) and does not crash. However, i cannot exit from the program. It just gets stuck. I even tried giving an exit(0) in the end but it didn't work.
Can you please tell me what's wrong?
#include<iostream.h>
#include<conio.h>
#include<stdio.h>
#include<ctype.h>
#include<string.h>
#include<process.h>
typedef char* string;
void main()
{
clrscr();
string s;
cout << "\nEnter something : ";
gets(s);
int i;
for (i = 0; i < strlen(s); ++i)
{
if ( s[i] != 32 )// && ( !isalnum(s[i-1]) || i == 0 ) )
{
char *word = s;
int end = 0;
for (; s[i] != 32 && i < strlen(s); ++i);
if (i == strlen(s)) end = 1;
else * (word + i) = '\0';
cout << "\n" << word;
if (end) break;
strcpy(s, s+i+1);
i = -1;
}
}
}
Undefined Behavior
You declare a pointer and don't initialize it (you don't make it point to anything):
string s;
// a.k.a. char * s;
Next, you input into it:
gets(string);
This is known as undefined behavior: writing to an unknown address. A nice operating system and platform would segfault.
In computer programming, you need to allocate memory either by using an array:
char s[256];
or dynamic allocation:
string s = new char[256];
before you put values in, either from input or elsewhere.
You told it to do that. Remove system("pause");
And, please, stop using the C library, and headers/tools from the 1980s. We've moved on from MS DOS in the intervening time. If you want marketable skills, learn actual ISO C++ (which was invented in 1998, and has been updated three times in the nearly two decades since then).
I wrote some code in order to turn a string (read in with getline()) into an array of c_strings. The problem I'm having is that the items I'm reading is not being stored in the array properly. I originally parsed the input based on the number of spaces in between them, and then going on from there, but that also got me the same problem. So I changed my parsing into what's below me, and I'm getting the same exact problem, suggesting to me that my parsing works, but somewhere in the process of reading what's parsed into the char* array, something is going wrong.
My code:
int i = 0;
unsigned inputSize = input.size();
unsigned int prev = 0; //prev as in previous space position
while((prev = input.find(' ', prev)) < inputSize) {
++i; ++prev;
}
char* charArray[i + 2];
memset(charArray, '\0', i + 2);
stringstream ss(input);
string buffer;
for(int a = 0; ss >> buffer; ++a) {
charArray[a] = const_cast<char*>(buffer.c_str());
}
What I'm doing is that I'm counting the number of spaces of my input, and making a char* array of that number + 2 (+2 because I need to end it with NULL). After that, I parse my input and read it into the array. I am using ss >> buffer as my termination clause because I will not end up allocating memory outside the allocated memory for charArray. buffer.c_str gets me a const char*, so I const_cast it in order for me to store it into the (non-const) array of char*. I use memset to set all elements to NULL because I know it'll be written over, except the last element, which I want to remain NULL.
Test:
Input: Why hello world
Output: Junk
What's going wrong inside my program?
The pointer returned by buffer.c_str() is valid only as long as the string stored in buffer is not modified. If you need to modify buffer, you have to copy its contents beforehand, if you need the old content later on.
See Right way to split an std::string into a vector [duplicate].
Live Example
#include <iostream>
#include <sstream>
#include <iterator>
#include <vector>
using namespace std;
int main(int argc, char *argv[]) {
std::string input = "Why hello world";
std::stringstream ss(input);
std::vector<std::string> vstrings(std::istream_iterator<std::string>(ss),
std::istream_iterator<std::string>{}); // C++11 brace syntax
char** charArray = new char*[vstrings.size()];
for (unsigned int i = 0; i < vstrings.size(); i++)
charArray[i] = (char*)vstrings[i].c_str();
for (unsigned int i = 0; i < vstrings.size(); i++)
std::cout << charArray[i] << "\n";
delete[] charArray;
}