I'm doing a C++ project for a PCB assembly thesis and I have been given (by my professor) an old set of C++ code. When I try test and run the code it chrashes...the program compiles ok, but it chrashes at runtime..here is the code:
main.cpp:
#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
#include <ctime>
#include <climits>
#include "NozzleBank.h"
#include "PlacementHead.h"
int main (int argc, char * const argv[]) {
std::vector<char> list;
for (int i=0; i<3; i++) {list.push_back('a');}
for (int i=0; i<3; i++) {list.push_back('b');}
for (int i=0; i<3; i++) {list.push_back('c');}
for (int i=0; i<3; i++) {list.push_back('d');}
for (int i=0; i<3; i++) {list.push_back('_');}
int i = 0;
char set[list.size()];
while (!list.empty()) {
int x = (rand() % list.size());
set[i] = list.at(x);
list.erase(list.begin()+x);
i++;
}
NozzleBank bank(15,set);
PlacementHead head(4,2,1,"abababab");
return 0;
}
PlacementHead.cpp:
#include "PlacementHead.h"
#include <string>
#include <iostream>
#include <string.h>
PlacementHead::PlacementHead(int width, int height, int gap, char* s) {
width_ = width;
height_ = height;
gap_ = gap;
size_ = (width*height)+1;
set_ = new char[size_];
from_ = new int[size_];
original_ = new char[size_];
strcpy(set_,s);
strcpy(original_,s);
}
PlacementHead::~PlacementHead() {
}
int PlacementHead::getSize() { return size_; }
int PlacementHead::getHeight() { return height_; }
int PlacementHead::getWidth() { return width_; }
int PlacementHead::getGap() { return gap_; }
// Palauttaa indeksissä i olevan suuttimen
char PlacementHead::getNozzle(int i) {
return set_[i-1];
}
// Asettaa indeksissä i olevan suuttimen
void PlacementHead::setNozzle(int i, char c) {
set_[i-1] = c;
}
// Merkitsee suuttimen poimituksi poistamalla sen listasta
void PlacementHead::markNozzle(int i, int bankPos) {
set_[i-1] = ' ';
from_[i-1] = bankPos;
}
// Palauttaa seuraavan poimimattoman suuttimen indeksin
int PlacementHead::getNextUnmarkedPos() {
for (int i=0; i<size_; i++) {
if (set_[i]!=' ') {
return i+1;
}
}
return 0;
}
// Palauttaa suuttimen alkuperäisen sijainnin pankissa
int PlacementHead::getBankPos(int i) {
return from_[i-1];
}
// Plauttaa alkuperäisen ladontapaan suutinjärjestyksen
void PlacementHead::reset() {
//for (int i=0; i<size_; i++) {
// set_[i] = original_[i];
//}
strcpy(set_,original_);
}
// Tulostusmetodi
void PlacementHead::print() {
std::cout << "ladontapää:\n";
for (int h=height_; h>0; h--) {
for (int w=width_; w>0; w--) {
int i = ((h-1)*width_)+w;
std::cout << getNozzle(i);
}
std::cout << "\n";
}
}
NozzleBank.cpp:
#include "NozzleBank.h"
#include <string>
#include <iostream>
#include <string.h>
NozzleBank::NozzleBank(int size) {
bank_ = new char[size];
original_ = new char[size];
size_=size;
for (int i=0; i<size_; i++) {
bank_[i] = ' ';
original_[i] = ' ';
}
}
NozzleBank::NozzleBank(int size, char* s) {
bank_ = new char[size];
original_ = new char[size];
size_ = size;
strcpy(bank_,s);
strcpy(original_,s);
}
NozzleBank::~NozzleBank() {
}
int NozzleBank::getSize() { return size_; }
// Palauttaa pankin alkuperäisen järjestyksen
void NozzleBank::reset() {
strcpy(bank_,original_);
}
// Asettaa indeksissä i olevan suuttimen
void NozzleBank::setNozzle(int i, char c) {
bank_[i-1] = c;
original_[i-1] = c;
}
// Palauttaa indeksissä i olevan suuttimen
char NozzleBank::getNozzle(int i) {
return bank_[i-1];
}
// Poimii suuttimen poistamalla sen listasta
void NozzleBank::pickNozzle(int i) {
bank_[i-1] = ' ';
}
// Tulostusmetodi
void NozzleBank::print() {
for (int i=size_; i>0; i--) {
std::cout << bank_[i-1];
}
}
When I run the program I get the following:
Now here is also an interesting thing: IF I switch the order of the following lines in main.cpp
NozzleBank bank(15,set);
PlacementHead head(4,2,1,"abababab");
to:
PlacementHead head(4,2,1,"abababab");
NozzleBank bank(15,set);
The program runs fine...:O? And here I get like whaaaat...I'm a bit newbie in C++ so I'd appreciate if someone could see what's the problem :) Thank you for any help!
The C library strcpy() requires a NUL terminated C style string. You have a char[] array that does not have a NUL terminator.
If you want to convert your randomized array of letters into a C-style string, you need to add one more element to the end, and set it to the value 0. Alternately, you need to turn your strcpy() calls into memcpy() calls and supply the length directly.
In terms of minimal code changes, adding a NUL terminator requires the fewest changes to your code. Change this:
char set[list.size()];
to this:
char set[list.size() + 1];
set[list.size()] = 0;
And then change all of your new char[size_] calls to new char[size_ + 1].
The cleaner approach would be to say what you mean, and treat this as an array of char, not a C string. Convert all your strcpy calls to memcpy. For example, this:
strcpy(set_,s);
strcpy(original_,s);
becomes this:
memcpy(set_,s,size_);
memcpy(original_,s,size_);
Note: Be sure to change all strcpy to memcpy on these arrays. I think there is at least one other. I did not check your code that closely.
The latter is the better approach, IMHO, but I offer both.
Also, the above code leaks memory. That may not be a concern if it just runs through once and quits. You new [] memory that you never delete []. If your program is going to grow and have multiple instances of these objects coming and going, you'll want to add those delete[] calls, otherwise you're setting yourself up for a future crash of a different sort.
One of the possible problems here is that you are using strcpy
strcpy works by reading an array of characters until it reaches a null terminating character '\0' - However your source array does not contain a null terminating character. so strcpy will keep copying forever, reading memory it doesn't have access to, and writing past the end of your destination array, either of which could cause the crash. You need to either use strncpy (which you should always prefer), which only copies a fixed number of characters.
You should in general always leave an extra space in any character array if you intend on treating the characters as a string, like strcpy does. If you are only using individual elements and treating the individual characters on their own, then you don't need to. You could equally use memcpy in that case.
There may be other problems in the code, this is just one I have spotted.
You also have memory leaks, you should delete[] the member variables you new[]
Related
So I have this header given to me
int mystrcpy(char *c, const char* s);
And I have to implement strcpy function myself. But when I do it and run the program, the console stops working, which I believe is a sign of memory address violation.
I tried this:
int mystrcpy(char *c, const char* s)
{
int i=0;
for(i=0;i<strlen(s);i++)
c[i]=s[i];
c[++i]=NULL;
cout<<c;
return 0;
}
Full code:
#include<iostream>
#include<cstring>
using namespace std;
class Persoana
{
char *nume;
int an;
float inaltime;
public:
int my_strcpy(char *c, const char*s);
};
int Persoana::my_strcpy(char *c, const char* s)
{
//code I need to insert
return 0;
}
int main()
{
Persoana a;
cout << endl;
cout<<a.my_strcpy("maria","george");
return 0;
}
Other posters have posted implementations of strcpy - Why you are using this in C++ code? That is an interesting question as C++ very rarely uses C style strings
The other problem is with its usage:
int main()
{
Persoana a;
cout << endl;
cout<<a.my_strcpy("maria","george");
return 0;
}
The strings "maria" and "george" are read only. Instead create an empty read/ write string as shown below that is long enough - i.e. 7 characters (do not forget the null character)
So the code should be
int main()
{
Persoana a;
char copy_of_string[7];
cout << endl;
cout<<a.my_strcpy(copy_of_string,"george");
return 0;
}
Your loop itself is OK (but inefficient, since you call strlen() on every iteration). The real problem is when you go to insert the null terminator at the end of the copied string. You are incrementing i again before inserting the terminator. DON'T do that. i is already at the correct index after the loop ends, so just use it as-is:
int mystrcpy(char *c, const char* s);
{
int i, len = strlen(s);
for(i = 0; i < len; ++i)
c[i] = s[i];
c[i] = '\0'; // <-- NO ++ HERE!
cout << c;
return 0;
}
That being said, the simplest way to implement strcpy without using i at all is as follows:
int mystrcpy(char *c, const char* s)
{
char *p = c;
while (*p++ = *s++);
cout << c;
return 0;
}
If you remove the cout then it becomes simpler:
int mystrcpy(char *c, const char* s)
{
while (*c++ = *s++);
return 0;
}
No matter what, make sure that when you call mystrcpy(), c is pointing to a char[] buffer that is allocated to at least strlen(s)+1 chars in size, otherwise the code will have undefined behavior.
The for loop
for(i=0; i < strlen(s); i++)
aborts when i < strlen(s) becomes false, which is the case when i is equal to strlen(s). So that will be the value of i when the loop ends.
C strings are NULL-terminated as you know, so you need strlen(s) + 1 bytes reserved for c. Since you increment i again before writing the '\0' character, you're using strlen(s) + 2 bytes starting at c.
If c is exactly the size that's needed (strlen(s) + 1), that may lead to an access violation, since you're writing past the end of the allocated memory.
So instead of
c[++i]=NULL;
write
c[i]='\0';
Hope this makes sense!
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];
}
}
Im trying to write a powerset to a file, but I get a heap corruption if my starting array is bigger than size 6, and im not sure why. It works fine with any size of array 6 or under. Cant figure this out.
Also, test.txt is where I read in the array. If the file contains"1,2,3,4,5,6" it works fine, but it it contains "1,2,3,4,5,6,7" I get heap corruption.
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
#include "N26.h"
#include <math.h>
using namespace std;
void increaseArray(int* theArray, int size)
{
int i = size;
int n = i+1;
int* newArray = new int[n];
for(int cnt=0;cnt<n;cnt++)
{
newArray[cnt] = theArray[cnt];
}
newArray[n-1]= NULL;
theArray = newArray;
return;
}
void printPowerSet(int *s, int n)
{
int i=0,j=0;
ofstream myFile;
double SetSize=pow(2.0,n);
myFile.open("powerset1.txt", std::ios_base::app);
cout<<"{size of original}"<< n <<endl;
cout<<"{number of sets}"<< SetSize-1 <<endl;
for(i=1;i<SetSize;++i)
{
for(j=0;j<n;++j)
{
if(((i>>j)&1)==1)
{
myFile << s[j] <<",";
}
}
myFile<<endl;
}
return;
}
int main()
{
ifstream myFile;
int item;
string input ="";
string fileName = "test.txt";
myFile.open(fileName);
while(myFile)
{
int k = 1;
int* transaction= new int[1];
if(!getline(myFile,input))
break;
istringstream ss(input);
while(ss)
{
if(!getline(ss,input, ','))
break;
input.erase(remove_if(input.begin(), input.end(), isspace), input.end());
item = atoi(input.c_str());
transaction[k-1] = item;
increaseArray(transaction,k);
k++;
}
for(int i =0; i<k-1;i++)
{
cout << transaction[i];
}
printPowerSet(transaction, k-1);
cout << endl;
transaction=NULL;
}
system("Pause");
return 0;
}
Your increaseArray() function doesn't work because you're only changing a local copy of the pointer. You'd have to pass a double pointer or a pointer reference to do what you want.
Example of a reference to pointer:
void increaseArray(int*& theArray, int size)
Instead, I'd recommend using a std::vector, since this will grow automatically.
I doubt this has any bearing on your problem, but I don't see that you ever delete, either. You are leaking memory. Before reassigning your pointer with a new allocation, delete the old allocation:
delete [] theArray; // The "[]" is important!
theArray = newArray;
In addition to Fred's answer.
Look at what's going on inside increaseArray(), specifically these lines:
int i = size;
int n = i+1;
int* newArray = new int[n];
for(int cnt=0;cnt<n;cnt++)
{
newArray[cnt] = theArray[cnt];
}
You allocate an array of size + 1 elements, and then iterate over the original. That's off-by-one, i.e. you are accessing one element outside of the original array. That might get you a segmentation fault depending on how new lays out the heap, but sure is undefined behavior.
how do I pass a char vector to a char*? I know this problem could easily be solved with a predefined char[] array with a SIZE const, but I want the flexibility of a vector because there will be no predefined size.
using namespace std;
//prototype
void getnumberofwords(char*);
int main() {
//declare the input vector
vector<char> input;
/*here I collect the input from user into the vector, but I am omitting the code here for sake of brevity...*/
getnumberofwords(input);
//here is where an ERROR shows up: there is no suitable conversion from std::vector to char*
return 0;
}
void getnumberofwords(char *str){
int numwords=0;
int lengthofstring = (int)str.size();
//this ERROR says the expression must have a case
//step through characters until null
for (int index=0; index < lengthofstring; index++){
if ( *(str+index) == '\0') {
numwords++;
}
}
}
You can use data() member to get the pointer to the underlying array:
getnumberofwords(input.data());
The most obvious is to pass &your_vector[0]. Be sure to add a NUL to the end of your vector first though.
Alternatively, use std::string instead of std::vector<char>, in which case you can get a NUL-terminated string with the c_str member function.
Edit: I have to wonder, however, why getnmberofwords would be written to accept a char * unless it's some old C code that you just can't get away from using.
Given a typical definition of "word" counting some words that start out in a string can be done something like this:
std::istringstream buffer(your_string);
size_t num_words = std::distance(std::istream_iterator<std::string>(buffer),
std::istream_iterator<std::string>());
You should pass the reference of the vector to the function getnumberofwords.
void getnumberofwords(vector<char>& str){
int numwords=0;
int lengthofstring = str.size();
for (int index=0; index < lengthofstring; index++){
if ( str[index] == '\0') {
numwords++;
}
}
}
There is no method for converting the type from vector to pointer.
here's what I ended up doing which worked:
#include <iostream>
#include <cstring>
#include <string>
#include <iomanip>
using namespace std;
//prototype
void getnumberofwords(char*);
void getavgnumofletters(char*, int);
int main() {
const int SIZE=50;
char str[SIZE];
cout<<"Enter a string:";
cin.getline(str, SIZE);
getnumberofwords(str);
return 0;
}
void getnumberofwords(char *str){
int numwords=0;
int lengthstring=strlen(str);
//step through characters until null
for (int index=0; index < lengthstring; index++){
if (str[index] ==' ') {
numwords++;
}else{
continue;
}
}
numwords+=1;
cout<<"There are "<<numwords<<" in that sentence "<<endl;
getavgnumofletters(str, numwords);
}
void getavgnumofletters(char *str, int numwords) {
int numofletters=0;
double avgnumofletters;
int lengthstring=strlen(str);
//step through characters until null
for (int index=0; index < lengthstring; index++){
if (str[index] != ' ') {
numofletters++;
}else{
continue;
}
}
avgnumofletters = (double)numofletters/numwords;
cout<<"The average number of letters per word is "<<setprecision(1)<<fixed<<avgnumofletters<<endl;
}
/*
Can someone help me with this: This is a program to find all the permutations of a string of any length. Need a non-recursive form of the same. ( a C language implementation is preferred)
using namespace std;
string swtch(string topermute, int x, int y)
{
string newstring = topermute;
newstring[x] = newstring[y];
newstring[y] = topermute[x]; //avoids temp variable
return newstring;
}
void permute(string topermute, int place)
{
if(place == topermute.length() - 1)
{
cout<<topermute<<endl;
}
for(int nextchar = place; nextchar < topermute.length(); nextchar++)
{
permute(swtch(topermute, place, nextchar),place+1);
}
}
int main(int argc, char* argv[])
{
if(argc!=2)
{
cout<<"Proper input is 'permute string'";
return 1;
}
permute(argv[1], 0);
return 0;
}
Another approach would be to allocate an array of n! char arrays and fill them in the same way that you would by hand.
If the string is "abcd", put all of the "a" chars in position 0 for the first n-1! arrays, in position 1 for the next n-1! arrays, etc. Then put all of the "b" chars in position 1 for the first n-2! arrays, etc, all of the "c" chars in position 2 for the first n-3! arrays, etc, and all of the "d" chars in position 3 for the first n-4! arrays, etc, using modulo n arithmetic in each case to move from position 3 to position 0 as you are filling out the arrays.
No swapping is necessary and you know early on if you have enough memory to store the results or not.
A stack based non-recursive equivalent of your code:
#include <iostream>
#include <string>
struct State
{
State (std::string topermute_, int place_, int nextchar_, State* next_ = 0)
: topermute (topermute_)
, place (place_)
, nextchar (nextchar_)
, next (next_)
{
}
std::string topermute;
int place;
int nextchar;
State* next;
};
std::string swtch (std::string topermute, int x, int y)
{
std::string newstring = topermute;
newstring[x] = newstring[y];
newstring[y] = topermute[x]; //avoids temp variable
return newstring;
}
void permute (std::string topermute, int place = 0)
{
// Linked list stack.
State* top = new State (topermute, place, place);
while (top != 0)
{
State* pop = top;
top = pop->next;
if (pop->place == pop->topermute.length () - 1)
{
std::cout << pop->topermute << std::endl;
}
for (int i = pop->place; i < pop->topermute.length (); ++i)
{
top = new State (swtch (pop->topermute, pop->place, i), pop->place + 1, i, top);
}
delete pop;
}
}
int main (int argc, char* argv[])
{
if (argc!=2)
{
std::cout<<"Proper input is 'permute string'";
return 1;
}
else
{
permute (argv[1]);
}
return 0;
}
I've tried to make it C-like and avoided c++ STL containers and member functions (used a constructor for simplicity though).
Note, the permutations are generated in reverse order to the original.
I should add that using a stack in this way is just simulating recursion.
First one advice - don't pass std:string arguments by value. Use const references
string swtch(const string& topermute, int x, int y)
void permute(const string & topermute, int place)
It will save you a lot of unnecessary copying.
As for C++ solution, you have functions std::next_permutation and std::prev_permutation in algorithm header. So you can write:
int main(int argc, char* argv[])
{
if(argc!=2)
{
cout<<"Proper input is 'permute string'" << endl;
return 1;
}
std::string copy = argv[1];
// program argument and lexically greater permutations
do
{
std::cout << copy << endl;
}
while (std::next_permutation(copy.begin(), copy.end());
// lexically smaller permutations of argument
std::string copy = argv[1];
while (std::prev_permutation(copy.begin(), copy.end())
{
std::cout << copy << endl;
}
return 0;
}
As for C solution, you have to change variables types from std::string to char * (ugh, and you have to manage memory properly). I think similar approach - writing functions
int next_permutation(char * begin, char * end);
int prev_permutation(char * begin, char * end);
with same semantics as STL functions - will do. You can find source code for std::next_permutation with explanation here. I hope you can manage to write a similar code that works on char * (BTW std::next_permutation can work with char * with no problems, but you wanted C solution) as I am to lazy to do it by myself :-)
Have you tried using the STL? There is an algorithm called next_permutation which given a range will return true on each subsequent call until all permutations have been encountered. Works not only on strings but on any "sequence" type.
http://www.sgi.com/tech/stl/next_permutation.html
This solves the problem without recursion. The only issue is that it will generate duplicate output in the case where a character is repeated in the string.
#include<iostream.h>
#include<conio.h>
#include<stdio.h>
#include<string.h>
int factorial(int n)
{
int fact=1;
for(int i=2;i<=n;i++)
fact*=i;
return fact;
}
char *str;
void swap(int i,int j)
{
char temp=str[i];
str[i]=str[j];
str[j]=temp;
}
void main()
{
clrscr();
int len,fact,count=1;
cout<<"Enter the string:";
gets(str);
len=strlen(str);
fact=factorial(len);
for(int i=0;i<fact;i++)
{
int j=i%(len-1);
swap(j,j+1);
cout<<"\n"<<count++<<". ";
for(int k=0;k<len;k++)
cout<<str[k];
}
getch();
}
#include <iostream>
#include <string>
using namespace std;
void permuteString(string& str, int i)
{
for (int j = 0; j < i; j++) {
swap(str[j], str[j+1]);
cout << str << endl;
}
}
int factorial(int n)
{
if (n != 1) return n*factorial(n-1);
}
int main()
{
string str;
cout << "Enter string: ";
cin >> str;
cout << str.length() << endl;
int fact = factorial(str.length());
int a = fact/((str.length()-1));
for (int i = 0; i < a; i++) {
permuteString(str, (str.length()-1));
}
}