map giving some ambiguous value - c++

The output expected is "2a3b3c4d3l4z" but
i'm getting:12a3b3c4d3l4z.
Why the extra "1" is coming in the output?
char ipstr[] = "aabbbcccddddzzzzlll";
cout<<"size of string:"<<sizeof(ipstr)<<endl;
num = 0;
map<char, int> ms;
for(int i = 0; i<sizeof(ipstr);i++){
if(ipstr[i] == ipstr[i+1])
num++;
else{
ms[ipstr[i]] = num+1;
num = 0;
}
}
for(auto it = ms.begin();it != ms.end();it++){
cout<<it->second<<it->first;
}
cout<<endl;

The extra 1 is the printout of the entry {'\0', 1} caused by taking the trailing '\0' into the loop. The \0 is not printable, therefore you see only 1.

You evaluated your string length including '\0' character (it can be ambigious that string ends with this one). Then in a for loop you added '\0' to the map. But what does it mean to print null character. That's why you have 1 and a whitespace at the beginning.
char ipstr[] = "aabbbcccddddzzzzlll";
int n = strlen(ipstr);
cout << "size of string:" << n << endl;
int num = 0;
map<char, int> ms;
for (int i = 0; i < n - 1; i++) {
if (ipstr[i] == ipstr[i + 1])
num++;
else {
ms[ipstr[i]] = num + 1;
num = 0;
}
}
for (auto it = ms.begin(); it != ms.end(); it++) {
cout << it->second << it->first;
}
cout << endl;

Related

Inserted in set and received Segmentation fault

I created code to convert graph representation (A list of edges -> the adjacency list)
How can i fix error?
I have Segmentation fault in line res[cur.first - 1].insert(cur.second);for input
4 3
3 2
2 1
4 2
My code
#include <bits/stdc++.h>
using namespace std;
pair<int, int> strToSotredPair(const string& s) {
int a = 0, b = 0;
int pos = 0;
while (s[pos] != ' ') {
a = a * 10 + s[pos] - '0';
++pos;
}
while (pos < s.size()) {
b = b * 10 + s[pos] - '0';
++pos;
}
return {min(a, b), max(a, b)};
}
int main() {
int n, m;
string input;
cin >> n;
cin >> m;
vector<set<int>> res(n, set<int>());
for (int i = 0; i < m; ++i) {
cin >> input;
auto cur = strToSotredPair(input);
res[cur.first - 1].insert(cur.second); // error in this line
}
for (int i = 0; i < res.size(); ++i) {
cout << res[i].size() << ' ';
for (auto item : res[i]) {
cout << item << ' ';
}
cout << endl;
}
}
There are a couple of error's in your code because of which you were getting that error.
You wanted the graph edges as strings. So you need to take edge inputs as strings. For that, you would be required to use getline(cin,input) and cin.ignore().
(My suggestion: Do not take inputs as strings because as it is you are converting them to integers afterwards. By default if you just write cin<<node1<<node2; the two nodes of an edge would have come as integers and function strToSotredPair would not be needed).
In function strToSotredPair after you get the integer a, pos variable is pointing to the space. So you need to increase it by 1 to point to the starting position to 2nd number. Hence a pos++ was needed.
#include <bits/stdc++.h>
using namespace std;
pair<int, int> strToSotredPair(const string& s) {
int a = 0, b = 0;
int pos = 0;
while (s[pos] != ' ') {
a = a * 10 + s[pos] - '0';
++pos;
}
pos++;
while (pos < s.size()) {
b = b * 10 + s[pos] - '0';
++pos;
}
return {min(a, b), max(a, b)};
}
int main() {
int n, m;
string input;
cin >> n;
cin >> m;
vector<set<int>> res(n, set<int>());
cin.ignore(); // To clear the input buffer
for (int i = 0; i < m; ++i) {
getline(cin, input); // to get line by line string inputs
auto cur = strToSotredPair(input);
res[cur.first - 1].insert(cur.second);
}
for (int i = 0; i < res.size(); ++i) {
cout << res[i].size() << ' ';
for (auto item : res[i]) {
cout << item << ' ';
}
cout << endl;
}
}

Program producing funky output

I am writing a program that takes in an input stream from std::cin and then fills a map container with all of the words(after removing all punctuation and making them lowercase) from the input along with their frequency.
here is my code...
#include "prog4.h"
void clean_entry(const string& s1, string& s2) {
for (int i = 0; i < s2.size(); i++) {//loop through the string
s2[i] = tolower(s2[i]);
}
}
void get_words(map < string, int >& map1) {
string input;
getline(cin, input);
string s1;
for (int i = 0; i < input.size(); i++ , s1 = "") {//loop through
entire input
if (isalnum(input[i]) == 0) {//if its a alphanumeric char
for (int d = i; isalnum(input[d]) == 0;d++) {//make s1 the
next set of characters between punctuation
s1 += input[d];
if (isalnum(input[d]) != 0)//update i to the next non
alfanumeric character position
i = d;
}
}
clean_entry(s1, s1);
map1[s1]++;
}
}
void print_words(const map < string, int >& m1) {
map<string, int>::const_iterator it;
cout << "Number of non-empty words: " << m1.size() << '\n';
int count = 0;
for (it = m1.begin(); it != m1.end(); it++) {
if (it->second == 1)
count++;
}
cout << "Number of distinct words: " << count << '\n';
it = m1.begin();
for (int y = 0; it != m1.end(); it++,y++) {
if (y % 3 == 0) {
cout << '\n';
}
cout << setw(20) << it->first << setw(10) << it->second;
}
}
int main() {
map <string, int> m1;
get_words(m1);
print_words(m1);
return 0;
}
I have tested the print and clean methods and they both work as expected. The problem I am getting is when I use the get_words method undoubtedly.
As an example when I use the input "Huge Muge Cuge luge" this is what I get as an output...
Number of non-empty words: 2
Number of distinct words: 0
16 3
I'm not sure what is causing this to happen and after reviewing the code I cant seem to find the problem which is why i'm posting here
Let me list out few problems which I can observe in your code.
The isalnum function returns non-zero value for alphanumeric characters.
That means the statement
if (isalnum(input[i]) == 0) { in function get_words should be changed to
if (isalnum(input[i]) != 0) {
Also, statement for (int d = i; isalnum(input[d]) == 0;d++) { should be changed to for (int d = i; isalnum(input[d]) != 0;d++) {
Another problem is that statement i = d; will not be executed as when for loop break it will skip those lines since conditions are just opposite. You can fix that by moving declaration of d out of for loop. The modified function should be:
=>
void get_words(map < string, int >& map1)
{
string input;
getline(cin, input);
string s1;
for (int i = 0; i < input.size(); i++ , s1 = "")
{
if (isalnum(input[i]) != 0)
{//if its a alphanumeric char
int d;
for (d = i; isalnum(input[d]) != 0;d++)
{
s1 += input[d];
}
if (isalnum(input[d]) == 0)
i = d;
}
clean_entry(s1, s1);
map1[s1]++;
}
}

C - strtok does strange things

i use strtok to split a string into different pieces and assemble them as a struct. This is my code:
object* parseJSON(size_t length, char* json, size_t jsonLen){
char *finalString = prepareJSON(json,jsonLen);
cout << finalString << "\n";
char delimiter[] = ",:";
char *token = strtok(finalString, delimiter);
object *retObj = (struct object *)malloc(length);
size_t returnObjectIndex = 0;
size_t index = 0;
bool firstTime = true;
struct object item;
while(token != NULL){
if((index % 2) != 0){
if(firstTime){
item.Type = token;
firstTime = false;
} else {
item.ID = token;
retObj[returnObjectIndex] = item;
returnObjectIndex++;
firstTime = true;
}
}
token = strtok(NULL,delimiter);
index++;
}
return retObj;
}
This is the finalString:
Type:temp,id:3,Type:temp,id:1
In my mind this should come out with this code:
for(int n = 0; n < 5; n++){
cout << returnObject[n].Type << " " << returnObject[n].ID << "\n";
}
as:
temp 3
temp 1
but instead i get this on the console:
temp 3
temp 1
h"° Ó*°
C
Is this because i loop 5 times even though there should be only 2 elements in the array? I loop 5 times because i can't get the number of elements of the array in the pointer (atleast i think that this is not possible).
Any help is very much appreciated
Best regards
Edit: This is my prepareJSON function:
char* prepareJSON(char* json, size_t jsonLen){
char forbiddenChars[] = {'[', '{','\"', '}', ']'};
bool isForbbidenChar = false;
char* finalString = (char*)malloc(jsonLen);
size_t finalStringIndex = 0;
for(size_t i = 0; i < jsonLen; i++){
char c = json[i];
isForbbidenChar = false;
for(int k = 0; k < 5; k++){
if(c == forbiddenChars[k]){
isForbbidenChar = true;
break;
}
}
if(isForbbidenChar){
continue;
}
else{
finalString[finalStringIndex] = c;
finalStringIndex++;
}
}
return finalString;
}
and this my main function:
int main(){
object *returnObject;
char json[] = "[{\"Type\":\"temp\",\"id\":\"3\"},{\"Type\":\"temp\",\"id\":\"1\"}]";
returnObject = parseJSON(5,json, strlen(json));
for(int n = 0; n < 5; n++){
cout << returnObject[n].Type << " " << returnObject[n].ID << "\n";
}
}
Solution:
I did indeed allocate too little memory, changed it:
object *retObj = (struct object *)malloc(sizeof(struct object) * length);
Now it works!

How can I reverse the words in a sentence without using built-in functions?

This was the interview question:
How to convert Dogs like cats to cats like Dogs ?
My code shows: cats like cats. Where am I making the mistakes?
#include <iostream>
using namespace std;
int main()
{
char sentence[] = ("dogs like cats");
cout << sentence << endl;
int len = 0;
for (int i = 0; sentence[i] != '\0'; i++)
{
len++;
}
cout << len << endl;
char reverse[len];
int k = 0;
for (int j = len - 1; j >= 0; j--)
{
reverse[k] = sentence[j];
k++;
}
cout << reverse << endl;
int words = 0;
char str[len];
for (int l = 0; reverse[l] != '\0'; l++)
{
if (reverse[l] == ' ' || reverse[l] == '\0') // not sure about this part
{
for (int m = l; m >= 0; m--)
{
str[words] = reverse[m];
words++;
}
}
}
cout << str;
return 0;
}
I know you can do this using pointers, stack, vectors... but interviewer was not interested in that!
This is a fixed version of your sample code:
Your principal problem is that every time you found and ' ' or '\0' you copy the bytes of the reverse string from the beginning to that point. Example in loop 5 you copy from index 0-5 (stac) from reverse to str in reverse order, but in in loop 10 you copy from index 0-10 (stac ekil) from reverse to str in reverse order, until here you have already the printed result string ('cats like cats'), and the same in loop 15 all of this incrementing the index of str, in the last loop you are written pass the end of the valid memory of str (and because of that not printed as output).
You need to keep track when end the last word reversed to reverse only the actual word, and not the string from the beginning to the actual index.
You don't want to count the special character (' ' and '\0') in the reversing of the words, you would end with cats like\0dogs
Modified sample code provided:
#include <iostream>
using namespace std;
int main() {
char sentence[] = ("dogs like cats");
cout << sentence << endl;
int len = 0;
for (int i = 0; sentence[i] != '\0'; i++) {
len++;
}
cout << len << endl;
char reverse[len];
int k = 0;
for (int j = len - 1; j >= 0; j--) {
reverse[k] = sentence[j];
k++;
}
cout << reverse << endl;
int words = 0;
char str[len];
// change here added last_l to track the end of the last word reversed, moved
// the check of the end condition to the end of loop body for handling the \0
// case
for (int l = 0, last_l = 0; ; l++) {
if (reverse[l] == ' ' || reverse[l] == '\0')
{
for (int m = l - 1; m >= last_l; m--) { // change here, using last_t to
str[words] = reverse[m]; // only reverse the last word
words++; // without the split character
}
last_l = l + 1; // update the end of the last
// word reversed
str[words] = reverse[l]; // copy the split character
words++;
}
if (reverse[l] == '\0') // break the loop
break;
}
cout << str << endl;
return 0;
}
Some code, written with the restriction of using the most simple features of the language.
#include <iostream>
// reverse any block of text.
void reverse(char* left, char* right) {
while (left < right) {
char tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
int main() {
char sentence[] = "dogs like cats";
std::cout << sentence << std::endl;
// The same length calculation as sample code.
int len = 0;
for (int i = 0; sentence[i] != '\0'; i++) {
len++;
}
std::cout << len << std::endl;
// reverse all the text (ex: 'stac ekil sgod')
reverse(sentence, sentence + len - 1);
// reverse word by word.
char* end = sentence;
char* begin = sentence;
while (end < sentence + len) {
if (*end != ' ')
end++;
if (end == sentence + len || *end == ' ') {
reverse(begin, end - 1);
begin = end + 1;
end = begin;
}
}
std::cout << sentence << std::endl;
return 0;
}
Dissecting your algorithm in pieces. First, you find the length of the string, not including the null char terminator. This is correct, though could be simplified.
size_t len = 0;
for (int i = 0; sentence[i] != '\0'; i++) {
len++;
}
cout << len << endl;
This could easily be written simply as:
size_t len = 0;
while (sentence[len])
++len;
Next, you reverse the entire string, but the first defect surfaces. The VLA (variable length array) you declare here, (which you don't need and shouldn't use, as it is a C++ extension and non-standard) does not account for, nor set, a terminating null-char.
char reverse[len]; // !! should be len+1
int k = 0;
for (int j = len - 1; j >= 0; j--) {
reverse[k] = sentence[j];
k++;
}
// !! Should have reverse[k] = 0; here.
cout << reverse << endl; // !! Undefined-behavior. no terminator.
This temporary buffer string is not needed at all. There is no reason you can't do this entire operation in-place. Once we calculate len correctly, you simply do something like the following to reverse the entire sequence, which retains the null char terminator in proper position:
// reverse entire sequence
int i = 0, j = len;
while (i < j--)
{
char c = sentence[i];
sentence[i++] = sentence[j];
sentence[j] = c;
}
Next we move to where you try to reverse each internal word. Again, just as before, the buffer length is not correct. It should be len+1. Worse (hard to imagine), you never remember where you left off when finding the end point of a word. That location should be the next point you start checking for, and skipping, whitespace. Without retaining that you copy from current point all the way back to the beginning of the string. which essentially blasts cats over dogs.
int words = 0;
char str[len]; // !! should be len+1
for (int l = 0; reverse[l] != '\0'; l++)
{
if (reverse[l] == ' ' || reverse[l] == '\0') // not sure about this part
{
for (int m = l; m >= 0; m--) {
str[words] = reverse[m];
words++;
}
}
}
cout << str; //!! Undefined behavior. non-terminated string.
Once again, this can be done in-place without difficulty at all. One such algorithm looks like this (and notice the loop that reverses the actual word is not-coincidentally the same algorithm as reversing our entire buffer):
// walk again, reversing each word.
i = 0;
while (sentence[i])
{
// skip ws; root 'i' at beginning of word
while (sentence[i] == ' ') // or use std::isspace(sentence[i])
++i;
// skip until ws or eos; root 'j' at one-past end of word
j = i;
while (sentence[j] && sentence[j] != ' ') // or use !std::isspace(sentence[j])
++j;
// remember the last position
size_t last = j;
// same reversal algorithm we had before
while (i < j--)
{
char c = sentence[i];
sentence[i++] = sentence[j];
sentence[j] = c;
}
// start at the termination point where we last stopped
i = last;
}
Putting It All Together
Though considerably simpler to use pointers than all these index variables, the following will do what you're attempting, in place.
#include <iostream>
int main()
{
char s[] = "dogs like cats";
std::cout << s << '\n';
size_t len = 0, i, j;
while (s[len])
++len;
// reverse entire sequence
i = 0, j = len;
while (i < j--)
{
char c = s[i]; // or use std::swap
s[i++] = s[j];
s[j] = c;
}
// walk again, reversing each word.
i = 0;
while (s[i])
{
// skip ws; root 'i' at beginning of word
while (s[i] == ' ') // or use std::isspace
++i;
// skip until ws or eos; root 'j' at one-past end of word
j = i;
while (s[j] && s[j] != ' ') // or use !std::isspace
++j;
// remember the last position
size_t last = j;
while (i < j--)
{
char c = s[i]; // or use std::swap
s[i++] = s[j];
s[j] = c;
}
// start at last-left posiion
i = last;
}
std::cout << s << '\n';
return 0;
}
Output
dogs like cats
cats like dogs
My advise would be to break up the original string into an array of words, reverse that array. Then add those words to your reversed sentence with a space in between.
Since they asked for no libraries, I assumed no std::string, no vectors, nothing at all and so I wrote it in C.. the only thing used is printf. Everything else is from scratch :l
The idea is that you reverse the array first. Then split the array by space and reverse each word.
Example: http://ideone.com/io6Bh9
Code:
#include <stdio.h>
int strlen(const char* s)
{
int l = 0;
while (*s++) ++l;
return l;
}
void reverse(char* str)
{
int i = 0, j = strlen(str) - 1;
for(; i < j; ++i, --j)
{
str[i] ^= str[j];
str[j] ^= str[i];
str[i] ^= str[j];
}
}
void nulltok(char* str, char tok, int* parts)
{
int i = 0, len = strlen(str);
*parts = 1;
for (; i < len; ++i)
{
if (str[i] == tok)
{
str[i] = '\0';
++(*parts);
}
}
}
char* reverse_sentence(char* str)
{
char* tmp = str;
reverse(str);
int i = 0, parts = 0, len = strlen(str);
nulltok(str, 0x20, &parts);
while(parts--)
{
reverse(str);
str += strlen(str) + 1;
}
for(; i < len; ++i)
if (tmp[i] == '\0')
tmp[i] = 0x20;
return tmp;
}
int main(void)
{
char str[] = "dogs like cats";
printf("%s", reverse_sentence(str));
return 0;
}
My solution
#include<iostream>
#include<string.h>
using namespace std;
int main()
{
string str;
cout<<"enter the sentence"<<endl;
getline(cin,str);
char* pch;
pch = strtok((char*)str.c_str()," ");
string rev = "";
while(NULL != pch)
{
rev.insert(0,pch);
rev.insert(0," ");
pch = strtok(NULL," ");
}
cout<<"the reversed string is :"<<rev<<endl;
return 0;
}

C++: Implementing merge sort from scratch

I was trying to test my self and wanted to write mergesort, without actually looking up any code online, and to do it in a certain time period. I am stuck at this point where I cannot simply understand what I am doing wrong, since merge sort, as much as i remember, is to divide the strings up to the point where string is only 1 character and later on merge them back together. The code I've written below tries to do the exact thing. I was wondering whether I got the concept wrong, or just my implementation?
string merge(string str1, string str2) {
string final = "";
int i = 0, j = 0;
bool fromStr1 = false;
while(true) {
if(str1[i] < str2[j]) {
final += str1[i];
i++;
if(i == str1.size()) {
break;
}
}
else {
final += str2[j];
j++;
if(j == str2.size()) {
break;
fromStr1 = true;
}
}
}
if(fromStr1) {
for(int t = i; t < str1.size(); t++) {
final += str1[t];
}
}
else {
for(int t = j; t < str2.size(); t++) {
final += str2[t];
}
}
return final;
}
string mergeSort(string str1, int start, int end) {
if(end - start == 1)
return str1;
else {
int pivot = (end - start) / 2;
string newStr1 = mergeSort(str1, start, pivot);
string newStr2 = mergeSort(str1, pivot + 1, end);
return merge(newStr1, newStr2);
}
}
Note the changes:
#include <iostream>
#include <string>
using namespace std;
string merge(string str1, string str2) {
string final = "";
int i = 0, j = 0;
bool fromStr1 = false;
while (true) {
if (i >= (int)str1.size()) {
break;
}
if (j >= (int)str2.size()) {
fromStr1 = true; // changed the order of this with break!
break;
}
if (str1[i] < str2[j]) {
final += str1[i];
i++;
}
else {
final += str2[j];
j++;
}
}
if (fromStr1) {
for (int t = i; t < (int)str1.size(); t++) {
final += str1[t];
}
}
else {
for(int t = j; t < (int)str2.size(); t++) {
final += str2[t];
}
}
return final;
}
string mergeSort(string str1) {
int len = str1.size();
if (len <= 1)
return str1;
else {
string newStr1 = mergeSort(str1.substr(0, len / 2));
string newStr2 = mergeSort(str1.substr(len / 2, len - len / 2));
return merge(newStr1, newStr2);
}
}
int main()
{
cout << '"' << mergeSort("") << '"' << endl;
cout << '"' << mergeSort("a") << '"' << endl;
cout << '"' << mergeSort("ba") << '"' << endl;
cout << '"' << mergeSort("132") << '"' << endl;
cout << '"' << mergeSort("4321") << '"' << endl;
cout << '"' << mergeSort("54321") << '"' << endl;
return 0;
}
Output (ideone):
""
"a"
"ab"
"123"
"1234"
"12345"
This doesn't look right:
int pivot = (end - start) / 2;
string newStr1 = mergeSort(str1, start, pivot);
string newStr2 = mergeSort(str1, pivot + 1, end);
Don't you mean pivot=(end+start)/2? Or else mergeSort(str1, start, start+pivot) and mergeSort(str1, start+pivot+1, end)?
EDIT:
And your merge doesn't cope well with empty strings. You should have tested this function before hooking it up to mergeSort.
It's been ages since I used C++, but doesn't break immediately exit the loop? Because fromStr1 = true; is never reached in that case.