Queries on a string [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
It's a B problem in codeforces
http://www.codeforces.com/problemset/problem/598/B
and i submit this code, but i get Wrong Answer.
It's brute force nothing special, but iam new at problem solving.
#include <iostream>
#include<string>
using namespace std;
int main()
{
char x[10000];
scanf_s("%s",x);
int num;
scanf_s("%d",&num);
int *l = new int[num];
int *r = new int[num];
int *k = new int[num];
for(int i =0;i<num;i++)
{
scanf_s("%d,%d,$d",&l[i],&r[i],&k[i]);
}
char temp;
for(int i =0; i<num;i++)
{
for (int j =0;j<k[i];i++)
{
temp= x[l[i]-1];
x[l[i]-1]=x[r[i]-1];
x[r[i]-1]=temp;
}
}
printf("%s",x);
return 0;
}
Any idea what is wrong or does it need to be optimized ?Is there better way to handle with case of many queries entered ?

scanf is a C function. string is a C++ data type. C++ can often use C datatypes, but it is very rare that C can use C++ datatypes. scanf was written about 20 years before C++ existed and has no clue what a string is.
Next, scanf takes a variable arguments list. It has no clue if the parameter types are correct and cannot easily check. It assumes that the programmer knows what they are doing.
End result, it tries to place char data as specified by the %s format option into a string. The string is written over with incompatible data and undefined behaviour occurs.
Replace the scanf with
cin >> x;
and go all C++. Alternative is to eschew C++ and go C style:
char x[appropriate size goes here];
scanf("%s",x);
Don't know the appropriate size? That's going to be a problem. string resizes to fit. The char array expected by scanf cannot. If you read more data than you can fit, Undefined Behaviour.
In
scanf("%d",num);
%d says the programmer passed in a pointer to an integer, in this case it would be the location of num so that scanf can update the value stored at num with whatever was read. The value of num was passed in. scanf assumes this is a pointer and Undefined Behaviour results. Most likely whatever uninitialized garbage value that is in num is used as a memory location and some unsuspecting block of memory gets overwritten. This will cause problems at some point in the future when you actually need the data that was at that memory.
scanf("%d",&num);
or in C++
cin >> num;
The remaining problems are variations on the preceding two problems.
scanf("%d,%d,%d",l[i],r[i],k[i]);
needs pointers
scanf("%d,%d,%d",&l[i],&r[i],&k[i]);
and
printf("%s",x);
wants a char array, not a string.
printf("%s",x.c_str());
gets the char array equivalent to the string.
Recommendation: Compile with a higher level of intolerance to errors that the compiler can survive. In g++ I use at least -pedantic -pedantic-errors -Wall -Wextra -Werror.
On a logical front, your input is all unchecked. A user could type in "rutabaga" for num with possibly comical results as your program tries to deal with non-numeric input. Again Undefined Behaviour. The program could crash. It could lock up. It could impregnate a male Llama.
In C++
if (cin >> num)
will catch some but not all forms of bad input. If this test fails, the contents of num are undefined and should not be used. Further, the stream will be in an error state and unreadable until the error is acknowledged and cleared. In C the equivalent is
if (scanf("%d",&num) == 1)
if scanf read exactly one value, num, all is good. Any other number of values read means scanf did not succeed and the contents of num are undefined.

Related

How is static array expanding itself? [duplicate]

This question already has answers here:
Why is it that we can write outside of bounds in C?
(7 answers)
Is accessing a global array outside its bound undefined behavior?
(8 answers)
Undefined, unspecified and implementation-defined behavior
(9 answers)
Closed 11 months ago.
I wrote a code for entering element and displaying the array at the same time. The code works but since char A[4] is static memory why does not it terminate/throw error after entering more than four elements? Code:
#include <iostream>
using namespace std;
void display(char arr[],int n)
{
for(int i=0; i<n; i++)
cout<<arr[i]<<" ";
return;
}
int main()
{
char A[4];
int i=0;
char c;
for(;;)
{
cout<<"Enter an element (enter p to end): ";
cin>>c;
if(c=='p')
break;
A[i]=c;
i++;
display(A,i);
system("clear");
}
return 0;
}
Writing outside of an array by using an index that is negative or too big is "undefined behavior" and that doesn't mean that the program will halt with an error.
Undefined behavior means that anything can happen and the most dangerous form this can take (and it happens often) is that nothing happens; i.e. the program seems to be "working" anyway.
However maybe that later, possibly one million instructions executed later, a perfectly good and valid section of code will behave in absurd ways.
The C++ language has been designed around the idea that performance is extremely important and that programmers make no mistakes; therefore the runtime doesn't waste time checking if array indexes are correct (what's the point if the programmers never use invalid ones? it's just a waste of time).
If you write outside of an array what normally happens is that you're overwriting other things in bad ways, possibly breaking complex data structures containing pointers or other indexes that later will trigger strange behaviors. This in turn will get more code to do even crazier things and finally, some code will do something that is so bad that even the OS (that doesn't know what the program wants to do) can tell the operation is nonsense (for example because you're trying to write outside the whole address space that was given to the process) and kills your program (segfault).
Inspecting where the segfault is coming from unfortunately will only reveal what was the last victim in which the code is correct but that was using a data structure that was corrupted by others, not the first offender.
Just don't make mistakes, ok? :-)
The code works but since char A[4] is static memory why does not it terminate/throw error after entering more than four elements?
The code has a bug. It will not work correctly until you fix the bug. It really is that simple.

How Integers initialize in C++? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
#include <iostream>
#include <math.h>
using namespace std;
class ip{
private:
string ip;
int result[8];
int sum;
public:
void input(){
/* cout<<"Enter First 8 Binary in Ip address: ";
cin>>ip;
for(int i=0,j=7;i<8 ,j>=0;++i,--j){
if(ip[i]=='1'){
result[i]=pow(2,j);
}else if(ip[i]=='0'){
result[i]=0;
}
}
for(int i=1 ; i<8 ; ++i){
sum=sum+result[i];
} */
cout<<sum<<"\n";
}
};
int main() {
ip convert;
convert.input();
return 0;
}
I was getting some problem while running this code then I understood the problem is with integer initialization...
please help me as I'm getting unwanted output
after running this code my output is: 131
I expected '0' as output
why is it so
You're right, one problem is that you don't initialise sum to zero. Also int i = 1 should surely be int i = 0.
sum=0;
for(int i=0 ; i<8 ; ++i){
sum=sum+result[i];
There are lots of other problems with the code including unnecessary use of a class, unnecessary use of class variables, unnecessary use of floating point functions, unnecessary use of temporary array etc. etc. This program could be much simpler.
In C++, Automatic storage duration integer variables are not initialized to any particular value, and will contain whatever garbage bit pattern that happens to already be in those memory locations. From the perspective of the language standard, the value of the variable is indeterminate, and using it leads to undefined behavior. If you had defined it as a static variable, it would be auto-initialized to 0 in C++.
Most likely your compiler will also throw a warning if you try to use a uninitialized variable.
In GCC, you will see the warning if you compile with below flag:
-Wuninitialized
Warn if an automatic variable is used without first being initialized or if a variable may be clobbered by a setjmp call. In C++, warn if a non-static reference or non-static const member appears in a class without constructors.
Update based on Peter's comment:
In the above case, the code creates an automatic storage duration object of that class type. However, since you just declare an object of type ip as ip convert and you don't have your own constructor which initializes class objects' member values, compiler's default constructor will be called. Most compilers (if not all) will not initialize member values for you and hence you see an output corresponding to the bit pattern present in the memory locations where the object got created.

Program crashes with message "terminate called recursively" without throwing any exception [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I was making a simple C++ program using CTable - my custom class. CTable contains a pointer to an array of int, which can be resized and manipulated with CTable methods.
Here's a short snippet:
class CTable
{
private:
int *table; //pointer to the table
int length; //length of the table
///...etc
public:
int SetLength(int length); //returns -1 on failure
int SetValueAt(int index, int value); //returns -1 on failure
///...etc
CTable& operator+=(CTable &other) //combine 2 CTables together
{
int oldLength = length;
SetLength(length+other.GetLength());
for(int i=oldLength;i<length;i++)
{
SetValueAt(i,other.GetValueAt(i-oldLength));
}
return *this;
}
};
I also have another function that I use to split user input into words:
vector<string>* splitString(string sentence, char delim)
{
vector<string> *res = new vector<string>();
stringstream ss;
ss.str(sentence);
string word;
while (getline(ss,word,delim))
{
res->push_back(word);
}
return res;
}
It is important to note that all the methods presented here seem to work fine on their own, i.e. when I test them individually.
As you can see I have also overloaded the += operator. The problem is that whenever I use this operator, the next user input crashes the program when the splitString() function is called. The program crashes with the sole error message "terminate called recursively". No exceptions is thrown, nothing. Only an error code 0xC0000005
I can't really show you the entire code because the program got pretty big, currently about 1000 lines of code. I try to fix this program for hours and I have no idea what's going on. Any help is greatly appreciated !
The windows error code 0xC0000005 means STATUS_ACCESS_VIOLATION. This is typically caused by problem with pointers, out of bound array accesses, memory corruption and other serious issues.
The splitString() function looks ok, so it certainly not causes by itself the kind of behavior you're describing.
The operator+=() looks more suspicious. The code itself seems ok, but it makes assumptions that SetLength() changes the length, reallocates the pointer, and copies all the existing values, all without any problem. Note by the way that this code doesn't handle special case such as doing += on one self.
Unfortunately, the signature of this function is int SetLength(int length);. So the name of the parameter hides the name of the member length, which could cause some serious mismatches that could lead to buffer overflows or unchanged member length (unless you use this->length and length to make the difference between the two).
Finally, you are using raw pointers instead of smart pointers. So you must ensure the rule of 3. If you don't, you will end-up with shallow copies which could also lead to UB (when one of the object releases the memory that it's copy is still using).

Array causes stack overflow error

My program is this:
#include<iostream>
#include<fstream>
using namespace std;
int main()
{
char choice;
int o,i,marks[i],ttlcredit=0;
double ttlGPA=0,finalGPA=0,credit[7][2],clsavg;
cout<<"Please enter what you want to calculate"<<endl;
cout<<"A for calculating Class Average GPA"<<endl;
cout<<"B for calculating a Specific GPA"<<endl;
cout<<"Your choice is? ";
cin>>choice;
cout<<endl;
if (choice == 'A'||choice == 'a')
{
cout<<"=========================================="<<endl;
cout<<" Class Average GPA"<<endl;
cout<<"=========================================="<<endl<<endl;
cout<<"Please enter the number of students in the class: ";
cin>>number;
for(i=0;i<number;i++)
{
cout<<"\nEnter student #"<<i+1<<"'s marks: ";
cin>>marks[i];
ttlGPA=ttlGPA+marks[i];
}
clsavg=ttlGPA/number;
cout<<"\nThe Average is: "<<clsavg<<endl;
}
else
{
}
}
It is half completed. When I build and run on CodeBlocks, an error instantly appeared:
I tried finding the source of error and I think that it is caused by the following in the code:
int o,i,marks[i],ttlcredit=0;
What makes me think so is because when I remove the [i] from marks[i], I will be not receive that error.
I think is stack overflow because I use Microsoft Visual Studio to help me debug and this is the error they gave me:
Unhandled exception at 0x0041419e in Project (1).exe: 0xC00000FD: Stack overflow.
My question is...
Is that the main cause of problem?
How do I resolve this issue?
You have to initialize the marks array with a positive length.
Get the number of students first, THEN create the array using that number.
Also, you need to declare the variable number.
As the other answers stated correctly, the problem is that int i is used uninitialized. However, the proposed fix
// initialze i
int marks[i];
is not standard C++, but only available through a compiler extension. In C++, the length of a built-in array must be a compile time constant. The better solution would be using std::vector:
// initialize i (better make it std::size_t instead of int)
std::vector<int> marks (i);
This will create a variable length array in a safe and standard conforming way.
First thing to say is that you simply shouldn't use arrays. They just are too weird in C and C++, and we have superior alternatives in modern C++.
Anyway, whether you use arrays or vectors, there are some important issues. Before discussing marks[i], it's simpler to look at credit[7][2] in this code.
int o,i,marks[i],ttlcredit=0;
double ttlGPA=0,finalGPA=0,credit[7][2],clsavg;
The dimensions are explicit in this declaration of credit. It's seven-times-two. Simple enough. You can read and write to credit[0][0] and credit[6][1] and many other values. But if you go outside the range, e.g. try to use credit[7][0], your program will compile and will probably appear correct for a while, but it could behave very badly and it is undefined how it will behave. It could decide to delete all the files on your computer, it is (seriously) entitled to do anything random and crazy. This is Undefined Behaviour.
Anyway, the really weird line is the declaration of marks.
int marks[i];
This definitely doesn't do what you think it does. It doesn't create an array that can be "indexed with arbitrary i". No, it allocates an array whose size is the initial value of i. But i is undefined at this stage so this is meaningless.
But i isn't relevant here anyway. How big do you want this array to be? The answer is number, isn't it? That is the number of people you'll store in your array.
So, a small improvement is to do this instead of int marks[i].
int marks[number];
But even this isn't correct. The value of number isn't set until the line cin >> number;, therefore you must declare int marks[number] after the line cin >> number; in order to ensure that marks has the correct size.
But, but, but, even after all this, we still don't have standard C++. It's OK to do int credit[7][2] because the size is fixed at compile time. You are normally not allowed to set the size of an array at runtime, e.g. int marks[number]. You might be able to use it if your compiler allows this extension (it's called Variable Length Array, from C).
So, this is not standard C++, and it's potentially very dangerous (see the Undefined Behaviour). What's the solution?
The solution is the standard solution for any problem involving arrays. Stop using arrays. (Really advanced programmers, in particular situations, might use std::array in modern C++, or even write their own clone of std:: array in older C++. But raw C [] arrays are to be avoided where possible.)
#include<vector>
int o,i,ttlcredit=0;
std::vector<int> marks;
marks is initially empty. We don't do cin >> marks[i];. Instead we use push_back to append new items to the end of the list.
int next_mark;
cin >> next_mark;
marks.push_back(next_mark);
Also, don't use marks[i] with a vector. It might look OK, but it is dangerous. Better to use marks.at(i) to read or write the element. at will do bounds checking for you, giving you a proper error message if i is too small (less then 0) or too big for the size of the vector.
int o,i,marks[i],ttlcredit=0;
i is not initialized. initialize i first.
If you are not sure of the size of the array, allocate it dynamically.
use new
refer this link on how to use new - cpluspluss

char* issue in C++ [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
Why this fragment of code does not work? I know that all entered strings have length less than 20 symbols.I do not use std::string because I want to learn how to use char*
#include <map>
#include <stdio.h>
using namespace std;
map <char*,int> cnt;
int main()
{
char ans[20];
int n,mx = 0;
scanf("%d\n",&n);
for ( int i = 1; i <= n; i++){
char str[20];
gets(str);
cnt[str]++;
}
for ( auto i = cnt.begin(); i != cnt.end(); i++ )
puts(i->first);
}
Let's be clear that your code has a lot of undefined behavior. I tried running your code and here is what I saw on my machine. You should tell us what your behavior was though because it's impossible to say what's going on for you otherwise.
First off, here was my program input.
3
hello
world
cat
And the output...
cat
char str[20] is a memory address, and that address is being reused by the compiler. Let's say that memory address is 0xABCD.
So on the first iteration, the map contains one element which is { 0xABCD, 1 }. On the second iteration it contains the same element with its value incremented, {0xABCD, 2}. On the third iteration it contains {0xABCD, 3}. Then when you go to print the map, it finds only one element in the map, and prints that memory address. This memory address happens to contain the word "cat", so it prints cat.
But this behavior is not reliable. The array char str[20] doesn't exist outside of the for loop, so sticking it into map <char *, int> cnt and even worse printing the array outside the loop are both undefined behavior.
If you want your code to work, I suppose you could do this....
for ( int i = 1; i <= n; i++){
char * str = new char[20];
gets(str);
cnt[str]++;
}
for ( auto i = cnt.begin(); i != cnt.end(); i++ )
puts(i->first);
for ( auto i = cnt.begin(); i != cnt.end(); i++ )
delete[](i->first);
But really, the correct strategy here is to either....
1) Use std::string
or
2) Don't use std::map
If you want to use C strings beyond converting them to std::string, then program without the use of the C++ std library. Stick to the C standard library.
Seems like cnt is std::map<char*, ...>. When you do cnt[str] you use pointer to local variable str as key, but str is only valid during single iteration. After that str is freed (semantically, optimizer may reuse it, but it is irrelevant here) and pointer to it is no longer valid.
It's very simple: when you allocate a C-style array as a local variable (char str[20];), it is allocated on the stack. It behaves just like any other object that you allocate as a local variable. And when it falls out of scope, it will be destroyed.
When you try to pass the array to the map in cnt[str], the array name decays to a pointer to the first element (it implicitely converts an expression of type char[20] into an expression of type char*). This is something radically different than an array. The map only ever sees this single pointer and stores it as the key. The map does not dereference the pointer to find out what's behind it, it just uses the memory location.
To fix your code, you need to do two things:
You need to allocate memory for your strings on the heap, so that the char* remains valid after the end of the scope. The easiest way to do this is to use the getline() or getdelim() functions available in the POSIX-2008 standard: These beautiful two functions will actually do the malloc() call for you. However, you still need to remember to free the string afterwards.
Making the map aware that you are talking about strings and not about memory addresses is much harder to achieve. If you must use a map, you likely need to define your own std::string-like wrapper class. But I guess, since you are playing around with the char* to learn their use, it would be more prudent to use some other kind of list and program the logic to check whether the given string is already in the list. Could be an array of char*, probably sorted to save lookup time, or a linked list, or whatever you like. For ease, you can just use an std::vector<char*>, but don't forget to free your strings before letting the vector fall out of scope.