character array and printf makes program slow - c++

(Um,My english is not well) :)
My friend is learning C++ now,and he find a problem that I can't explain why.
The First Code ,it runs more than 2000MS
#include <cstdlib>
#include <cstdio>
#include <cstring>
using namespace std;
int ans[2000000];
char a[2000000];
int main()
{
scanf("%s\n",a);
int l=1,r=strlen(a);
for (int i=0;i<strlen(a);i++)
if (a[i]=='l')
ans[r--] = i+1;
else
ans[l++] = i+1;
for (int i=1;i<=strlen(a);i++)
printf("%d\n",ans[i]);
return 0;
}
The Second Code,it runs 465MS
#include <cstdlib>
#include <cstdio>
#include <cstring>
using namespace std;
int ans[2000000];
char a[2000000];
int size;
int main()
{
scanf("%s",a);
int l=1,r=strlen(a);
size = r;
for (int i=0;i<strlen(a);i++)
if (a[i]=='l') ans[r--]=i+1;else ans[l++]=i+1;
for (int i=1;i<=size;i++)
printf("%d\n",ans[i]);
return 0;
}
The Third Code,it runs more than 2000MS
#include <cstdlib>
#include <cstdio>
#include <cstring>
using namespace std;
int ans[2000000];
char a[2000000];
int size;
int main()
{
scanf("%s",a);
int l=1,r=strlen(a);
size = r;
for (int i=0;i<size;i++)
if (a[i]=='l') ans[r--]=i+1;else ans[l++]=i+1;
for (int i=1;i<=strlen(a);i++)
printf("%d\n",ans[i]);
return 0;
}
The Last Code ,it runs 515MS
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
using namespace std;
int ans[2000000];
string a;
int main()
{
cin >>a;
int l=1,r=a.size();
for (int i=0;i<a.size();i++)
if (a[i]=='l') ans[r--]=i+1;else ans[l++]=i+1;
for (int i=1;i<=a.size();i++)
printf("%d\n",ans[i]);
return 0;
}
When input string size is 10^5
So , the reason is about second for loop.
And my question is why "strlen" function and print in for loop will make the code so slow?

By writing strlen in the loop condition — a loop with two million iterations — you are scanning through a two-megabyte string two million times. Of course that's going to take some time!
That delay goes away when you pre-calculate the string length just once.
Also, you will probably find that streaming 2MB of text to the console is going to be noticeably "slow" in any case.

The strlen function has to be executed each time through the loop when you have it in the loop. That's an extra function call, and it has to run through the full string to find it's length.
Caching the length in size, means that none of that has to be redone every time through the loop.
So, there is no error. This is expected behavior.

Related

Exercise to verify if a word == it's reverse

I've come into some problem with my code. At a first glance, it seems that I've done everything right and the code should work. But, it isn't. This exercise asks me to verify if a word is equal to it's reverse.
This is my code:
#include <iostream>
#include <cstring>
using namespace std;
int main(){
char cuv[255], cuv1[255]=""; cin>>cuv;
int j = strlen(cuv)-1;
for(int i = 0; i<strlen(cuv); i++)
cuv1[i]=cuv[j-i];
cuv1[strlen(cuv1)+1]='\0';
if(cuv==cuv1)
cout<<"cuvantul este palindrom";
else
cout<<"cuvantul nu este palindrom";
return 0;
}
This becomes much easier with std::string and std::equal:
std::string cuv = "ANNA";
return std::equal(std::begin(cuv), std::end(cuv), std::rbegin(cuv));
Or if for some reason you want to stick with C strings:
char cuv[255] = "ANNA";
int len = strlen(cuv);
return std::equal(cuv, cuv+len, std::reverse_iterator<char*>(cuv+len));
This method works fine, I've gave up trying to compare the words, so I compared the word's letters from start with those from the end.
#include <iostream>
#include <cstring>
using namespace std;
int main(){
char cuv[255]; cin>>cuv;
int n = strlen(cuv);
int k = 0;
for(int i = 0; i!=strlen(cuv)/2;i++)
if(cuv[i]!=cuv[n-i-1])
k=1;
if(k==0)
cout<<"cuv pal";
else
cout<<"cuv != pal";
return 0;
}
problem is with this statement
cuv1[strlen(cuv1)+1]='\0'
Change this to
cuv1[strlen(cuv1)]='\0';

How to change the order of an array in c++

I am try to change the order of an array of char like this :
char arr_char[]="ABCDEFGHIJABCDEFGHIJ";
i used the rand() function in the following code :
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main()
{
char arr_char[]="ABCDEFGHIJABCDEFGHIJ";
int arrSize=sizeof(arr_char)-1;
srand(time(0));
for(int i=0;i<20;i++)
{
cout<<arr_char[rand() % arrSize]<<" ";
}
}
but the rand function repeat some characters more than twice and i want to change the order of the array in which every characters repeat only twice not more .
This will probably suffice
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string arr_char = "ABCDEFGHIJABCDEFGHIJ";
random_shuffle(arr_char.begin(), arr_char.end());
cout << arr_char;
}

Segmentation fault in reversing string program

I am trying to reverse a string. Can someone explain me why this is giving me segmentation fault?
#include <iostream>
#include <string>
using namespace std;
int main(){
string str,rstr;
int len=str.length(),i=0;
cin>>str;
while(str[i]!='\0'){
rstr[--len]=str[i++];
}
rstr[str.length()]='\0';
cout<<rstr;
return 0;
}
P.S.: Need to reverse it without using library functions.
If you want to go the way you are doing it, for practice purposes, try this changes and start from there
#include <iostream>
#include <string>
using namespace std;
int main(){
string str,rstr;
cin>>str; // --- Moved this line up
rstr = str; // --- Added this line
int len=str.length(),i=0;
while(str[i]!='\0'){
rstr[--len]=str[i++];
}
rstr[str.length()]='\0';
cout<<rstr;
return 0;
}
Or just use reverse iterator
std::string s = "Hello";
std::string r(s.rbegin(), s.rend());
str is nothing but a declared string here:
int len=str.length(),i=0;
So you can't do str.length()
Do something like:
#include <iostream>
#include <string>
using namespace std;
int main(){
string str,rstr;
int len,i=0;
cin>>str;
len = str.length();
while(str[i]!='\0'){
rstr[i++]=str[--len];
}
rstr[str.length()]='\0';
cout<<rstr;
return 0;
}

C++ Array pointer-to-object error

I am having what seems to be a common issue however reading through the replies to the similar questions I can't find the solution to my issue at all as I have already done what they are suggesting such as making the variable an array. I have the following code:
#include "stdafx.h"
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>
#include <algorithm>
#include <future>
using namespace std;
string eng2Str[4] = { "money", "politics", "RT", "#"};
int resArr[4];
int main()
{
engine2(eng2Str[4], resArr[4]);
system("Pause");
system("cls");
return 0;
}
void engine2(string &eng2Str, int &resArr)
{
ifstream fin;
fin.open("sampleTweets.csv");
int fcount = 0;
string line;
for (int i = 0; i < 4; i++) {
while (getline(fin, line)) {
if (line.find(eng2Str[i]) != string::npos) {
++fcount;
}
}
resArr[i] = fcount;
}
fin.close();
return;
}
Before you mark as duplicate I have made sure of the following:
The array and variable I am trying to assign are both int
Its an array
The error is:
expression must have pointer-to-object type
The error is occurring at the "resArr[i] = fcount;" line and am not sure why as resArr is an int array and I am trying to assign it a value from another int variable. I am quite new to C++ so any help would be great as I am really stuck!
Thanks!
The problem is that you've declared your function to take a reference to a single string and int, not arrays. It should be:
void engine2(string *eng2Str, int *resArr)
or:
void engine2(string eng2Str[], int resArr[])
Then when you call it, you can give the array names as arguments:
engine2(eng2Str, resArr);
Another problem is the while loop in the function. This will read the entire file during the first iteration of the for() loop. Other iterations will not have anything to read, since it will be at the end of the file already. You could seek back to the beginning of the file, but a better way would be to rearrange the two loops so you just need to read the file once.
while (getline(fin, line)) {
for (int i = 0; i < 4; i++) {
if (line.find(eng2Str[i]) != string::npos) {
resArr[i]++;
}
}
}
I would suggest to use std::vector instead of pure C array.
In your code, there are more issues.
You are passing the fourth element of both arrays to the engine2 function.
From your definition of void engine2(string &eng2Str, int &resArr) you expect reference to a string (not array / vector) and an address / reference of int - you need to pass an pointer to the first element of resArr.
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <future>
using namespace std;
vector<string> eng2Str = { "money", "politics", "RT", "#" };
int resArr[4] = {};
void engine2(const vector<string>& eng2Str, int* resArr)
{
ifstream fin;
fin.open("sampleTweets.csv");
int fcount = 0;
string line;
for (int i = 0; i < 4; i++)
{
while (getline(fin, line))
{
if (line.find(eng2Str[i]) != string::npos)
{
++fcount;
}
}
resArr[i] = fcount;
}
fin.close();
return;
}
int main()
{
engine2(eng2Str, resArr);
system("Pause");
system("cls");
return 0;
}

Segmentation Fault while Reading from File

I am trying to print last 10 lines of a file. Following is my code, but it is giving a segmentation fault due to fscanf. While running with gdb the fault reads : vfscanf.c: No such file or directory.
#include <iostream>
#include <stdio.h>
#include <string>
using namespace std;
int main()
{
FILE *fp = fopen("microfile.txt","r");
char *c[10];
int idx = 0;
cout<<fp<<"\n";
while(!feof(fp))
{
if(idx<10)
{
fscanf(fp,"%s",c[idx]);
idx++;
}
else if(idx==10)
{
for(int i=0;i<idx-1;i++)
{
c[i] = c[i+1];
}
fscanf(fp,"%s",c[idx-1]);
}
}
int i=0;
while(i<10)
{
cout<<c[i]<<"\n";
i++;
}
}
The source of the problem comes from the fact you have an array of pointers on this line:
char* c[10];
And later on in the program you attempt to assign character values to these pointers. Maybe you meant for just an array of characters instead:
char c[10];
Moreover, use of the Standard library is recommended. Try using std::string and standard streams and your program can be made more maintainable:
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::string s;
s.assign(
std::istreambuf_iterator<char>(std::ifsteam("microfile.txt").rdbuf()),
std::istreambuf_iterator<char>());
for (char c : s)
std::cout << c << std::endl;
}