Mapping string to int CPP - Output hangs during execution - c++

I am currently doing a practice problem in hacker rank. The link is : https://www.hackerrank.com/challenges/linkedin-practice-dictionaries-and-maps
#include<cstdio>
#include<map>
#include<vector>
#include<conio.h>
#include<iostream>
#include<string>
using namespace std;
map<std::string, int> dict;
map<std::string, int>::iterator k;
int i, j, temp, n;
long long num;
//char check[100][100];
std::string str, sea;
int main()
{
scanf("%d", &n);
j = n;
while(j--)
{
scanf("%s %d", &str, &num);
dict.insert(make_pair(str, num));
}
printf("finished\n");
printf("%s %d\n", "sam", dict["sam"]);
while(scanf("%s", str))
{
if(str.empty())
break;
//printf("k is %s\n",str);
k = dict.find(str);
if(k != dict.end())
{
printf("%s %d\n", str, dict[str]);
}
else
{
printf("Not found\n");
}
}
getch();
}
The program runs fine until the printf statement "finished". Then in the next output for the dict statement occurs as
finished
sam 0
And in while statement, when it searches for string in map, the application hangs, and closes automatically. While inserting values I tried to use:
dict[str] = num;
dict.insert(pair(str, num));
dict.insert(make_pair(str, num));
Please mention if there is any corrections I need to do in the program. Any help is appreciated. Thanks!

This statement,
scanf("%s %d", &str, &num);
… is not a valid way to input a std::string. It has Undefined Behavior. All bets are off.
You can input to a char buffer, and conveniently std::string provides such a buffer. E.g.
str.resize( max_item_length );
scanf("%s %d", &str[0], &num);
str.resize( strlen( &str[0] ) );
Of course you can just use C++ iostreams instead, throughout the code, e.g.
cin >> str >> num;

Related

Cannot resolve EXC_BAD_ACCESS (code=EXC_I386_GBFLT)

I'm very new at C++, maintaining my M.Sc on Information Systems. I have my first C++ homework announced and have been working on it for a couple of days. The aim of the code is simply to read info from a text file and print it on screen, then make calculation on some of it and print results to a new text file. However when I build, it gives the error:
EXC_BAD_ACCESS (code=EXC_I386_GBFLT)
in the first fscanf in readInfo function.
I know the code I wrote is not completely efficient but I just want it to print on screen and on output file correctly. I would really appreciate if anyone help me to resolve this error. I am about to freak out...
#include <stdio.h>
typedef struct {
char id[10];
char name[40];
float midterm;
float final;
int attendance;
}Student;
void readInfo(Student studentList[], int *count)
{
FILE *fin=fopen("scores.txt","r");
char surname = '\0';
*count=0;
while(!feof(fin))
{
fscanf(fin,"%c %c %c %f %f %d",studentList[*count].id, studentList[*count].name, &surname, &studentList[*count].midterm, &studentList[*count].final, &studentList[*count].attendance);
strcpy(studentList[*count].name, studentList[*count].name);
strcat(studentList[*count].name, " ");
strcat(studentList[*count].name, &surname);
*count++;
}fclose(fin);
printf("%-7s%17s %5.1f %5.1f %-2d\n", studentList[*count].id, studentList[*count].name, studentList[*count].midterm, studentList[*count].final, studentList[*count].attendance);
}
float studentScore(float midterm, float final, int attendance)
{
float score;
int maxAttend=0;
char id[10];
char name[40];
char surname[40];
FILE *fin=fopen("scores.txt","r");
while(!feof(fin))
{
fscanf(fin,"%c %c %c %f %f %d",id, name, surname, &midterm, &final, &attendance);
if(attendance>maxAttend)
maxAttend=attendance;
}fclose(fin);
score=midterm*0.3+final*0.5+(maxAttend/20)*attendance;
return score;
}
float avgScore(Student studentList[])
{
float average;
int count;
int totalScore=0;
readInfo(studentList, &count);
for(int i=0; i<=count; i++)
{
totalScore+=studentScore(studentList[count].midterm, studentList[count].final, studentList[count].attendance);
}
average=totalScore/count;
return average;
}
void courseGradeOutput(Student studentList[])
{
FILE *fout=fopen("output.txt","w");
int count;
int pass=0;
float score;
char letterGrade[2];
float avg;
fprintf(fout,"\tId\tName, Surname = (Score, Letter)\n");
readInfo(studentList, &count);
for(int i=0; i<=count; i++)
{
score=studentScore(studentList[i].midterm, studentList[i].final, studentList[i].attendance);
if(score>=0 && score<=49)
{ letterGrade[0]={'F'};
letterGrade[1]={'F'};}
else if (score>=50 && score<=59)
{letterGrade[0]={'F'};
letterGrade[1]={'D'};}
else if (score>=60 && score<=64)
{letterGrade[0]={'D'};
letterGrade[1]={'D'};}
else if (score>=65 && score<=69)
{letterGrade[0]={'D'};
letterGrade[1]={'C'};}
else if (score>=70 && score<=74)
{letterGrade[0]={'C'};
letterGrade[1]={'C'};}
else if (score>=75 && score<=79)
{letterGrade[0]={'C'};
letterGrade[1]={'B'};}
else if (score>=80 && score<=84)
{letterGrade[0]={'B'};
letterGrade[1]={'B'};}
else if (score>=85 && score<=89)
{letterGrade[0]={'B'};
letterGrade[1]={'A'};}
else if (score>=90 && score<=100)
{letterGrade[0]={'A'};
letterGrade[1]={'A'};}
if(score>=60)
pass++;
fprintf(fout,"%7s %16s = ( %4.1f, %6s\n)", studentList[i].id, studentList[i].name, score, letterGrade);
}
avg=avgScore(studentList);
fprintf(fout,"\nSome statistics:\n\nClass Avg Score: %5.2f \n #Students: %11d \n #Passed Students: %4d \n #Failed Students: %4d",avg,count,pass,(count-pass));
fclose(fout);
}
int main()
{ Student studentList[100];
int count;
readInfo(studentList, &count);
courseGradeOutput(studentList);
}
Screenshot
The crash is most likely caused by either fscanf followed by strcpy and/or by your increment of count inside readInfo.
You write *count++, but this is equivalent to
count = count + 1;
*(count-1);
What you want is (*count)++.
The fscanf scans characters %c where you want to scan strings %s (for id and name). You also want to scan surname as a string, probably, but then you need to change surname to be a character array:
char surname[30];
*count=0;
while(!feof(fin))
{
fscanf(fin,"%s %s %s %f %f %d",studentList[*count].id, studentList[*count].name, surname, &studentList[*count].midterm, &studentList[*count].final, &studentList[*count].attendance);
strcat(studentList[*count].name, " ");
strcat(studentList[*count].name, surname);
(*count)++;
}
fclose(fin);
I also removed the first strcpy as you were copying from a buffer to itself, which is not allowed.
I haven't checked the other functions thoroughly, but I do notice that you do not use the result from your readInfo called from main when you do courseGradeOutput: this function calls readInfo again. You could modify it to take the read student records and the count, so you don't have to read the file again.
You might also want to improve scanf a bit to pass a width, such as %29s for name, to avoid overflowing the buffer when the name inside the file is too long; and the same for the other strings you scan. You should then also look at the return value of fscanf and only use the things you scanned when it succeeded in scanning every argument.

Why is this program(rather the segment) crashing the whole program

I have been scratching my head to figure out why is my program is crashing. My aim was to scan a string and get frequency of each sub string !
The Real part where the program is crashing (M is a map of string,int type)
My Input: the string is "abab" and the program crashes when i=0 and j is equal to 3 just at the M[e]++ statement!
for(i=0;str[i];i++)
{
char temp[5001];
k=0;
cout<<str[i]<<endl;
for(j=i;str[j];j++)
{
temp[k]=(char)str[j];
k++;
temp[k]='\0';
string e(temp);
M[e]++;
cout<<j<<endl;
}
}
MAIN Method
int main()
{
ini();
int t,N,i,j,Q,buff,k=0;
char str[5001];
scanf("%d",&t);
map <string ,int > M;
map <string , int >::iterator ii;
for(;t--;)
{
scanf("%d%d",&N,&Q);
scanf(" %s",str);
for(i=0;str[i];i++)
{
char temp[5001];
k=0;
cout<<str[i]<<endl;
for(j=i;str[j];j++)
{
temp[k]=(char)str[j];
k++;
temp[k]='\0';
string e(temp);
M[e]++;
cout<<j<<endl;
}
}
for(ii=M.begin();ii!=M.end();++ii)
F[ii->second]++;
F2[N]=F[N]%MOD;
for(i=N;i>=1;i--)
if(F[i])
for(j=i-1;j>=1;j--)
F2[j]=(F[j]+((long long)F[i]%MOD*C(F[i],j)%MOD)%MOD)%MOD;
for(i=0;i<Q;i++)
{
scanf("%d",&buff);
printf("%d\n",F2[buff]);
}
}
return 0;
}
Note
int F[5001],F2[5001];
are declared globally too.
As requested:
#include <iostream>
#include <string>
#include <map>
#define MOD 10
using namespace std;
int C( int a, int b ){
return 5;
}
int F[5001],F2[5001];
int main()
{
int t,N,i,j,Q,buff,k=0;
string str(5001, ' ');
cin >> t;//scanf("%d",&t);
cin.ignore( 256, '\n' );
map <string ,int > M;
map <string , int >::iterator ii;
for(;t--;)
{
cin >> N;
cin.ignore( 256, '\n' );
cin >> Q;
cin.ignore( 256, '\n' );
//scanf(" %s",str);
getline(cin,str);
for(i=0;str[i];i++)
{
char temp[5001];
k=0;
cout<<str[i]<<endl;
for(j=i;str[j];j++)
{
temp[k]=(char)str[j];
k++;
temp[k]='\0';
string e(temp);
M[e]++;
cout<<j<<endl;
}
}
for(ii=M.begin();ii!=M.end();++ii)
F[ii->second]++;
F2[N]=F[N]%MOD;
for(i=N;i>=1;i--)
if(F[i])
for(j=i-1;j>=1;j--)
cout << "hello";F2[j]=(F[j]+((long long)F[i]%MOD*C(F[i],j)%MOD)%MOD)%MOD;
for(i=0;i<Q;i++)
{
scanf("%d",&buff);
printf("%d\n",F2[buff]);
}
}
return 0;
}
For testing purposes, because there was no MOD and C definitions given, for MOD I used a constant int and C an empty function that received those parameters and simply returned a value.
Instead of scanf, I used cin for the inputs and later cin.ignore() to clear the input buffer so that it won't skip the next cin. Changed str to type string. Used getline to get input for string, as this reads the enitre line from the input cin. And that is it for modifications.
for(i=0;str[i];i++)
{
for(j=0;str[j+i];j++)
{
M[str.substr(j,i+1)]++;
}
}
Replace internal two for loops with this and check whether it's crashing or not . If still that means you may be running this program on windows.In that case use this.
for(i=0;str[i];i++)
{
for(j=0;str[j+i];j++)
{
std::string sstr = str.substr(j,i+1);
if ( M.find ( sstr ) == M.end() ){
M.insert( std::make_pair ( sstr , 0 ) ) ;
}
else
M[str.substr(j,i+1)]++;
}
}

Reverse String C++ using char array

I wrote a simple C++ program to reverse a string. I store a string in character array. To reverse a string I am using same character array and temp variable to swap the characters of an array.
#include<iostream>
#include<string>
using namespace std;
void reverseChar(char* str);
char str[50],rstr[50];
int i,n;
int main()
{
cout<<"Please Enter the String: ";
cin.getline(str,50);
reverseChar(str);
cout<<str;
return 0;
}
void reverseChar(char* str)
{
for(i=0;i<sizeof(str)/2;i++)
{
char temp=str[i];
str[i]=str[sizeof(str)-i-1];
str[sizeof(str)-i-1]=temp;
}
}
Now this method is not working and, I am getting the NULL String as result after the program execution.
So I want to know why I can't equate character array, why wouldn't this program work. And what is the solution or trick that I can use to make the same program work?
sizeof(str) does not do what you expect.
Given a char *str, sizeof(str) will not give you the length of that string. Instead, it will give you the number of bytes that a pointer occupies. You are probably looking for strlen() instead.
If we fixed that, we would have:
for(i=0;i<strlen(str)/2;i++)
{
char temp=str[i];
str[i]=str[strlen(str)-i-1];
str[strlen(str)-i-1]=temp;
}
This is C++, use std::swap()
In C++, if you want to swap the contents of two variables, use std::swap instead of the temporary variable.
So instead of:
char temp=str[i];
str[i]=str[strlen(str)-i-1];
str[strlen(str)-i-1]=temp;
You would just write:
swap(str[i], str[sizeof(str) - i - 1]);
Note how much clearer that is.
You're using C++, just use std::reverse()
std::reverse(str, str + strlen(str));
Global variables
It's extremely poor practice to make variables global if they don't need to be. In particular, I'm referring to i about this.
Executive Summary
If I was to write this function, it would look like one of the two following implementations:
void reverseChar(char* str) {
const size_t len = strlen(str);
for(size_t i=0; i<len/2; i++)
swap(str[i], str[len-i-1]);
}
void reverseChar(char* str) {
std::reverse(str, str + strlen(str));
}
When tested, both of these produce dlrow olleh on an input of hello world.
The problem is that within your function, str is not an array but a pointer. So sizeof will get you the size of the pointer, not the length of the array it points to. Also, even if it gave you the size of the array, that is not the length of the string. For this, better use strlen.
To avoid multiple calls to strlen, give the function another parameter, which tells the length:
void reverseChar(char* str, int len)
{
for(i=0; i<len/2; i++)
{
char temp=str[i];
str[i]=str[len-i-1];
str[len-i-1]=temp;
}
}
and call it with
reverseChar(str, strlen(str))
Another improvement, as mentioned in the comments, is to use std::swap in the loop body:
void reverseChar(char* str, int len)
{
for(i=0; i<len/2; i++)
{
std::swap(str[i], str[len-i-1]);
}
}
Also, there is std::reverse which does almost exactly that.
//reverse a string
#include<iostream>
using namespace std;
int strlen(char * str) {
int len = 0;
while (*str != '\0') {
len++;
str++;
}
return len;
}
void reverse(char* str, int len) {
for(int i=0; i<len/2; i++) {
char temp=str[i];
str[i]=str[len-i-1];
str[len-i-1]=temp;
}
}
int main() {
char str[100];
cin.getline(str,100);
reverse(str, strlen(str));
cout<<str<<endl;
getchar();
return 0;
}
If I were you, I would just write it like so:
int main()
{
string str;
cout << "Enter a string: " << endl;
getline(cin, str);
for (int x = str.length() - 1; x > -1; x--)
{
cout << str[x];
}
return 0;
}
This is a very simple way to do it and works great.
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
char str[80];
cout << "Enter a string bro: \n";
gets_s(str);
for (int i = strlen(str) - 1; i > -1; i--)
{
cout << str[i];
}
}

Why the code is printing 0 at first

#include <cstdio>
#include <string>
#include <set>
#include <sstream>
#include <iostream>
using namespace std;
int main()
{
int t, z;
scanf("%d", &t);
while (t--) {
string buf, str;
getline(cin, str);
stringstream ss(str);
int cnt = 0;
set<string> tokens;
while (ss >> buf) {
tokens.insert(buf);
}
for (set<string>::iterator it = tokens.begin(); it != tokens.end(); ++it) {
cnt++;
}
printf("%d\n", cnt);
}
return 0;
}
This code is just used for counting the number of different words present in a string. e.g for input
i am i
wil give output
2
But when i enter the test cases it first gives 0 as output neglecting the last test case..what is the reason for it?? and how can it be corrected??
Here is the link
Your scanf is only reading the integer - it doesn't read the end of line. So your first "line" is the rest of the line with "4" on it. Either read to the end of the line or use the solution from user3477950.
Sameer,
modify your code thus:
int main()
{
char eatNewline = '\0';
int t, z;
scanf("%d", &t);
eatNewline=getchar(); //Eat the enter key press.
while (t--)
{
string buf, str;
getline(cin, str);
stringstream ss(str);
int cnt = 0;
set<string> tokens;
while (ss >> buf)
{
tokens.insert(buf);
}
for (set<string>::iterator it = tokens.begin(); it != tokens.end(); ++it)
{
cnt++;
}
printf("%d\n", cnt);
}
return 0;
}
[root#saas ~]# ./tst
4
now do it now
3
now do it now
3
I am good boy
4
am am
1
Please let me know if that helps you! :)
because after you scanf("%d", &t), the tailing \n is still in the input string buffer.
To fix this problem, you can change it to:
scanf("%d ", &t); // add a space after %d to catch the '\n' character
or add
cin >> ws;
or use gets(...) etc.

Using struct and point to input and output info

I have a problem with inputting a string pointer in struct. This is my code:
typedef struct{
char *name;
int age;
}stu;
void allocate(stu* &s, int n){
s = (stu*) malloc(n * sizeof(stu));
if(s == NULL){
printf("\nNot enought memory!");
exit(1);
}
}
// Input info
void input_info(stu* &s, int n){
void input(stu &s); //prototype
for(int i = 0; i < n; i++){
printf("\n-- Student #%d:", i+1);
input(*(s+i));
}
}
void input(stu &s){
fflush(stdin);
printf("\nEnter student's name: ");
gets(s.name);
printf("\nEnter student's age: ");
scanf("%d", &s.age);
}
// End input
//Output info
void output_info(stu* s, int n){
void output(stu s); //prototype
for(int i = 0; i < n; i++){
printf("\n-- Student #%d:", i+1);
output(*(s+i));
}
}
void output(stu s){
printf("\nName: %s", s.name);
printf("\nAge: %d", s.age);
}
//End output
int main(){
stu* s;
int n;
printf("How many students you want to input?: ");
scanf("%d", &n);
allocate(s, n);
input_info(s, n);
output_info(s, n);
getch();
}
When I input second student's name, it's breaked? I allocated memory. And I want to ask how to deallocate memory for stu pointer? Thanks for reading
There are many things that can and should be improved in your program. Some suggestions:
Remove the char * member replace it with std::string. You don't want to do manual memory management for anything unless you really want to.
Drop the silly scanf and printf, they are not type safe. Since you are using C++ use std::cin and std::cout and you are much safer than usage with later.
Drop the fflush(stdin), Calling fflush on anything other than stdout gives you undefined behavior.
In C++, You would usually want to use new and not malloc. Avoid using dynamic memory allocation at all, if you can. Prefer to use a std::vector instead.
Online Sample:
Following the above suggestions your example can be written as:
#include<string>
#include<vector>
#include<iostream>
typedef struct
{
std::string name;
int age;
}student;
// Input info
void input_info(std::vector<student> &s)
{
student obj;
std::cout<<"\nEnter Students name";
std::cin>>obj.name;
std::cout<<"\nEnter Students age";
std::cin>>obj.age;
s.push_back(obj);
}
// Output info
void output_info(const std::vector<student> &s)
{
for (auto itr = s.cbegin(); itr != s.cend(); ++itr)
{
std::cout<<"\nName:"<< itr->name;
std::cout<<"\nAge:"<< itr->age;
}
}
int main()
{
int n;
std::cout<<"How many students you want to input?\n";
std::cin>>n;
std::vector<student>s;
for(int i = 0; i<n; i++)
{
input_info(s);
}
output_info(s);
return 0;
}
As some of the previous poster have mentioned, the code is not "pure" c++, as it mixes a lot of C and C++ features. Personally I think it is a less problematic when dealing with POD structs, like yours.
The crash is likely caused by gets(). It assumes that the char pointer is already allocated with a suitable capacity. It has undefined behavior when the inputs strings is longer than the capacity. Your capacity is 0, hence the crash.
If you insist on using C functions, see: Safe Alternative to gets.
Otherwise lookup getline().