So here is a function in a program that I am working on for class. IN the function, I want to combinations of a 8 character hand for 3,4,5,6,7 and 8 letter words that are validated with a checkDictionary function. Everything works fine and dandy but when I want to store these created words into a 2-d array of chars (basically a 1D array of strings) I get a segmentation fault error. The lines that are apparently causing these issues are the lines such as:
strcpy(arrWords[count],letters8);
strcpy(arrWords[count],letters7);
...
^ until letters3 ^
I just want to know what exactly is wrong with me storing into the 2d array with code lines such as those. Also if you could give me any suggestion on how to accurately store these created words into the 2d array (arrWords) it would be greatly appreciated. Thank you so much for your time! :D
miscellaneous:
this program is basically scrabble
the loops that increment i & j are used to increment through a 2d array board of 10x10 that is filled with "." and placed words by the user.
-the dictionary has 40438 actual words
void computerMove(char dictionary[][45], char arrBoard[11][11], char computer[9])
{
char let1, let2, let3, let4, let5, let6, let7, let8;
// char letters3[4];
// char letters4[5];
// char letters5[6];
// char letters6[7];
// char letters7[8];
// char letters8[9];
int count = 0;
char arrWords[40438][10];
for (int i=0; i<10; i++)
{
for (int j=0; j<10; j++)
{
// if (arrBoard[i][j]!='*')
let1=arrBoard[i][j];
for (int a=0; a<8; a++)
{
let2=computer[a];
for (int b=0; b<8; b++)
{
let3=computer[b];
char letters3[4]={let1,let2,let3};
cout<<letters3<<endl;
if (searchDictionary(dictionary,letters3,40438)==true)
strcpy(arrWords[count],letters3);
count++;
for (int c=0; c<8; c++)
{
let4=computer[c];
char letters4[5]={let1,let2,let3,let4};
if (searchDictionary(dictionary,letters4,40438)==true)
strcpy(arrWords[count],letters4);
count++;
for (int d=0; d<8; d++)
{
let5=computer[d];
char letters5[6]={let1,let2,let3,let4,let5};
if (searchDictionary(dictionary,letters5,40438)==true)
strcpy(arrWords[count],letters5);
count++;
for (int e=0; e<8; e++)
{
let6=computer[e];
char letters6[7]={let1,let2,let3,let4,let5,let6};
if (searchDictionary(dictionary,letters6,40438)==true)
strcpy(arrWords[count],letters6);
count++;
for (int f=0; f<8; f++)
{
let7=computer[f];
char letters7[8]={let1,let2,let3,let4,let5,let6,let7};
if (searchDictionary(dictionary,letters7,40438)==true)
strcpy(arrWords[count],letters7);
count++;
for (int g=0; g<8; g++)
{
let8=computer[g];
char letters8[9]={let1,let2,let3,let4,let5,let6,let7,let8};
if (searchDictionary(dictionary,letters8,40438)==true)
strcpy(arrWords[count],letters8);
count++;
}
}
}
}
}
}
}
}
// cout<<"YOURE OVER HERE PAL!"<<endl;
// for (int z=0; z<50; z++)
// cout<<arrWords[z]<<endl;
}
}
Thank you so much for trying to help!
strcpy is used for copying C-strings, not arrays.
This function looks for string ending null character '\0' for the source and destination inputs so that it knows where to stop copy operation. But in the case of array, it may not find this character for a long memory sequence and you get segmentation error.
Instead, you can use std::copy() like this:
std::copy(std::begin(letters3),std::end(letters3), arrWords[count] );
Related
I want to sort an array which contains names according to their length, but the following program gives a compiler error when I try to swap them using a function. Please help me identify my mistake.
void sort(char name1[][50])
{
for (int i = 0; i < 5; i++)
{
if (strlen(name1[i])>strlen(name1[i+1]))
{
char temp[50];
temp=name1[i];
name1[i]=name1[i+1];
name1[i+1]=temp;
}
}
}
Use strcpy() to copy one array to other
void sort( char name1[][50])
{
for(int i=0; i< 5; i++)
{
if(strlen(name1[i])>strlen(name1[i+1]))
{
char temp[50];
strcpy(temp,name1[i]);
strcpy(name1[i],name1[i+1]);
strcpy(name1[i+1],temp);
}
}
}
Use strcpy to copy c-string. First copy the first string into the temp string, then copy the second into the first, and finally the temp into the second string.
strcpy(temp,name1[i]);
strcpy(name1[i],name1[i+1]);
strcpy(name1[i+1],temp);
I'm working on a school project written in c++. I am trying to generate an array of rgb colours based on user input, for a program that generates fractals(irrelevant).
I found the need to use a pointer to a 2D array. The pointer has a global scope because it needs to be accessed across multiple files, in multiple functions.
There is no problem with the declaration of the pointer. It is as such:
in "global.h"
int **ptr;
int palette[10][3];
//all the statements like #ifndef GLOBAL_H_INCLUDED, etc are present
in main.cpp
extern int **ptr;
extern int palette[10][3];
void gen_array();
int main()
{
//initialize values of palette
//palette is basically list of colors that the user selects for the
//desired blend of colors to appear on the screen
gen_array();
}
in void gen_array(), in main.cpp
void gen_array()
{
int i=0, size=0, size_arr=0;
//size is a variable helpful in calculating "size_arr", which is the size of the dynamic array to be initialized
while(palette[i][0]!=256)
{ //calculates "size" }
for(int i=0; i<size-1; i++)
{
//to find "size_arr"
}
ptr= new int*[size_arr]();
for(int i = 0; i < size_arr; ++i)
{
ptr[i] = new int[3];
}
//the following piece of code enter's values column-wise into the array
int s=0;
for(int i=0; i<size-1; i++)
{
for(int k=0; k<3; k++)
{
int x=-1, a=0, b=0;
a= palette[i][k] - palette[i+1][k];
b= palette[i][k];
if(a<0)
{
a= -a;
x=1;
}
for(int j=0; j<=a; j++, s++)
{
ptr[i][k] = b;
//cout<<*(*(ptr+i)+k)<<' ';
b= b+ x;
}
b= b-x;
for(int j=a+1; j<=diff[i]; j++, s++)
{
ptr[i][k] = b;
cout<<ptr[i][k]<<' ';
}
cout<<endl;
}
}
//this output's the array that the pointer points to, on the screen
for(int i=0; i<size_arr; i++)
{
for(int j=0; j<3; j++)
{
cout<<ptr[i][j]<<' ';
}
cout<<endl;
}
}
The problem is that, the data is getting generated and inputted in the array correctly [in the second-last for loop], but when outputting it [the last for loop] I'm getting junk values.
The data inputted [the correct values] as obtained from the cout statements [that are now commented] is this [printed column-wise] whereas the O/P given out is this [printed row-wise].
If it is required to be know, "size" (in this case) =2, size_arr=256 and palette[0]={0, 0, 255} and palette[1]={0,255,0}.
Can anybody point out what the problem is, and whether it has something to do with the pointer initialization?
Even without reading all the program code like
for(int j=0; j<=a; j++, s++)
{
ptr[i][k] = b;
//cout<<*(*(ptr+i)+k)<<' ';
b= b+ x;
}
looks clearly wrong. At each iteration you are writing to ptr[i][k] and the loop doesn't change ptr, i or k. This means that it will keep writing to the very same location during the loop.
Look at your int i in the loop you're using to fill int** ptr. If size = 2 then you're never going to advance ptr far enough to fill the array. Consider filling the array like this:
for(int i = 0; i < size_arr; ++i){//for every pixel in the main array
for(int k = 0; k < 3; ++k){//for every subpixel
int my_value = ...;//calculate the value for this entry
*(*(ptr+i)+k) = my_value;//assign
Better yet, use a struct named pixel containing Uint8 r,g,b and allocate as pixel* ptr = new pixel[size] and iterate over pixels and assign ptr[i].r ptr[i].g ptr[i].b
So i'm trying to write a function which would get input from keyboard and store it in the 2d dynamic array. n is the number of lines (tried with 1-4 lines), m is the number of characters per line (256 in my case). I've read plenty about dynamic arrays and the use of new and the code seems totaly fine to me, but i keep getting this error when i try to enter the text: Access violation reading location 0x00000000. Can't figure out why. Please help.
void KeyInput (char **string, unsigned int n, unsigned int m)
{
cout<<endl<<"Input from keyboard"<<endl;
string=new char* [n];
for(unsigned int i = 0; i < n; i++ )
string[i]=new char[m];
for(unsigned int i = 0; i < n; i++ )
gets(string[i]);
}
can you give more information on where you are getting the access violation? I tried the following code (Visual Studio 2010, Window 7 Professional) and did not get an error. Note that I did change the characters per line to 15 instead of 255 as I wanted to test boundary conditions without a lot of typing.
Your function seems to work fine on my machine, however you do have a latent buffer-overflow using gets as it does not check for the length of the string. Remember that gets will append a null-terminator for you, so if in your case you enter exactly 255 characters you will overflow your buffer by one.
void KeyInput(char** string, unsigned int n, unsigned int m);
int _tmain(int argc, _TCHAR* argv[])
{
char* strArray;
KeyInput(&strArray, 4, 15);
return 0;
}
void KeyInput(char** string, unsigned int n, unsigned int m)
{
string = new char*[n];
for(unsigned int i = 0; i < n; i++)
{
string[i] = new char[m];
}
for(unsigned int i = 0; i < n; i++)
{
gets(string[i]);
}
}
(also ignore the hideous _tmain and _TCHAR stuff, they are Windows idiosyncrasies :) ).
Finally, unless this is an assignment (or an exercise for self learning), do what 40two suggested and use STL to make your life easy.
Use a vector of strings, take advantage of the force that STL has (use the force Luke see code below how):
void KeyInput (std::vector<std::string>& str_vec, int const n)
{
std::cout << "\nInput from keyboard" << std::endl;
for (auto i = 0; i < n; i++) {
std::string tmp;
std::getline(std::cin, tmp);
str_vec.push_back(tmp);
}
}
Update or Why your C++ teachers are wrong:
void KeyInput(char ***string, unsigned int n, unsigned int m)
{
std::cout << "\nInput from keyboard" << std::endl;
*string = new char*[n];
for (unsigned int i = 0; i < n; i++)
(*string)[i] = new char[m];
for (unsigned int i = 0; i < n; i++)
std::gets((*string)[i]);
}
int main()
{
char **string = 0;
KeyInput(&string, 4, 100);
for (auto i = 0; i < 4; ++i) std::cout << string[i] << std::endl;
return 0;
}
You need triple pointers in order to pass the 2d array by reference and to be properly filled (OMG!!!).
The user can enter only limited length strings (e.g., 99) don't forget strings have one character at the end (i.e., '/0' the null character).
You have to take care of the memory allocated and deleted later in order to avoid memory leaks.
If you want to shoot your self in the foot continue to program like this.
I have an assignment to create a block transposition cipher program. A user is to input a phrase of their choice, and the program is to strip the phrase of spaces, punctuation, and make lowercase, before reading its length and creating a two-dimensional array the size of the nearest square that will fit all the chars in the mutated string, and filling in the remaining space with random letters.
Problem is, I'm having issues with creating that square.
I have this so far:
int main()
{
string input;
cout << "Please enter message to cipher." << endl;
getline(cin, input);
/* do punctuation removal/mutation */
int strLength = input.length(); //after mutation
/* need to find the square here before applying sizes and values to arrays */
char * original = new char[][]; // sizes pending
char * transposed = new char[][]; // sizes pending
for (int i = 0; i <= /* size pending */ ; i++)
{
for (int j = 0; j <= /* size pending */ ; j++)
{
transposed[j][i] = original[i][j];
}
}
/* do more stuff here */
}
any ideas?
(I already have done the mutation portion; tested with alternate code)
You can't do e.g.
char * original = new char[][];
First of all you are trying to create an array of arrays (or pointer of pointers) and assign it to a single pointer. You need to do it in two steps:
Allocate the "outer" array:
char **original = new char* [size];
Allocate the "inner" strings:
for (int i = 0; i < size; i++)
original[i] = new char [other_size];
However I would highly recommend against using that! Instead you should be using std::vector instead of "arrays" allocated on the heap, and if the contents are strings then use std::string:
std::vector< std::vector< std::string > > original;
You can take the square root of the length, round down to an integer, and add one to get the new length.
int len = (int)(sqrt(strLength) + 1e-9) + 1;
You'd then malloc the square using len and fill as you normally would.
I believe you do not need the "new" to create your storage. Following code should just do the job:
char buf[size][size]; // size is a variable
... // populate your buf
char tmp;
for(int i = 0; i < size; i++) {
for(int j = 0; j < i; j++) {
tmp = buf[i][j];
buf[i][j] = buf[j][i];
buf[j][i] = tmp;
}
}
This does the transpose in place. You don't need another array to store the char's.
I want to read a raw file, which has 3 interleaving and has a size of about(3.5MB) large into a three dimensional array.. the code that I am using to read the file is:
ifile.open(argv[2], ios::in|ios::binary);
for(int i=0; i<1278; i++){
for(int j=0; j<968; j++){
for(int k=0; k<3; k++){
Imagedata1[i][j][k]=ifile.get();
}
}
}
The thing is this array is not what i expect it to be.. I need the 1278 to be the width of the image.. the 968 to be the height and 3 bytes are the RGB values.. how should i write the code to read from the file such that the array gets populated correctly.. Thanks.
First, image files are usually stored, in order of smallest jump to largest, color values, column, row order. You are not reading them in that order.
ifile.open(argv[2], ios::in|ios::binary);
for(int j=0; j<968; j++){
for(int i=0; i<1278; i++){
for(int k=0; k<3; k++){
Imagedata1[i][j][k]=ifile.get();
}
}
}
That is how the loop should be arranged, though you may want to rename your variables to keep things straight:
ifile.open(argv[2], ios::in|ios::binary);
for(int row=0; row<968; row++){
for(int col=0; col<1278; col++){
for(int color=0; color<3; color++){
Imagedata1[col][row][color]=ifile.get();
}
}
}
Secondly, the way you allocate your array is really broken and inefficient. Here is how it should work:
#include <iostream>
#include <fstream>
class ColorValue {
public:
ColorValue(unsigned char r, unsigned char g, unsigned char b)
: r_(r), g_(g), b_(b) {}
ColorValue() : r_(0), g_(0), b_(0) {}
unsigned char getR() const { return r_; }
unsigned char getG() const { return g_; }
unsigned char getB() const { return b_; }
private:
unsigned char r_, g_, b_;
};
void readrows(const char *fname, ColorValue imagedata[][1278])
{
::std::ifstream ifile;
ifile.open(fname, ::std::ios::in|::std::ios::binary);
for (int row = 0; row < 968; ++row) {
for (int col = 0; col < 1278; ++col) {
char r, g, b;
ifile.get(r);
ifile.get(g);
ifile.get(b);
imagedata[row][col] = ColorValue(r, g, b);
}
}
}
int main(int argc, const char *argv[])
{
ColorValue (*imagedata)[1278] = new ColorValue[968][1278];
readrows(argv[1], imagedata);
delete[] imagedata;
}
Using a class for ColorValue keeps you from having magic indexes everywhere in your code for the 'r', 'g', and 'b' components. And allocating the array in this way keeps all the memory used for the image contiguous and removes several levels of unnecessary indirection. These both have the property of making your program much more cache friendly.
I also found a nice article that's a really comprehensive treatment of multi-dimensional arrays in C++.
C arrays don't work like that.
Let's say you wanted a 2D 1024*768 pixel buffer, with 4 bytes per pixel. You'd do something like this:
unsigned int pixbuf[1024*768];
for (int irow=0; irow < 1024; irow++)
for (int icol=0; icol < 768; icol++)
pixbuf[(irow*1024)+icol] = icolor;
Here is a good link that explains further:
http://c-faq.com/~scs/cclass/int/sx9.html
'Hope that helps!
As long as you always access your data through the three-dimensional array it does not matter how the structure of the array is laid down in memory. In your example you define the first index (i) as the column index, the (j) index as the row index and the (k) index as the pixel component index.
I suspect your image file has the data organized in the standard way, which is an array of rows, where each row is an array of pixels, where each pixel is an array of color components. If that is the case, then you can modify your code to work with that structure:
ifile.open(argv[2], ios::in|ios::binary);
for(int i=0; i<1278; i++){
for(int j=0; j<968; j++){
for(int k=0; k<3; k++){
Imagedata1[j][i][k]=ifile.get();
}
}
}
Note that I just swapped the i and j indexes in the body of the innermost for loop, the rest of the code is identical to yours.
If you also need to access the image data as a planar buffer, then you should reorganize your arrays so that the data in memory mimics the layout from the file. For this you want the first dimension to be the rows, then columns, then color components. That would end up like this:
unsigned char Imagedata1[968][1278][3];
ifile.open(argv[2], ios::in|ios::binary);
for(int i=0; i<968; i++){
for(int j=0; j<1278; j++){
for(int k=0; k<3; k++){
Imagedata1[i][j][k]=ifile.get();
}
}
}
Update: after a quick discussion in the comments, it seems you do want to read this in a more efficient way. If you want to load this image on the stack (probably not a good idea) you would declare your image buffer as:
unsigned char Imagedata1[968][1278][3];
I would instead put it on the heap, like this:
unsigned char* Imagedata1 = new unsigned char[968*1278*3];
Then you can read the data from the file with:
if (fread(Imagedata1, 1278*3, 968, fd) != 968) {
// handle error here
}
Note that the numbers that you put as count and size in the fread call are not that important, as long as those two numbers multiplied are equal to width*height*components.
If you then need to access this image as a 3-dimensional array, I recommend that you create an auxiliary function, something like this:
unsigned char* getPixel(int col, int row)
{
return Imagedata1 + row * 1278 * 3 + col * 3;
}
The return value of this function can be used as a one dimensional array of three elements, the red, green and blue of the pixel.
As a final suggestion, I recommend that you wrap your image in a class, and add member variables that define the width and height (and maybe the number of color planes as well). You do not want to hardcode the 1278s and the 968s all over the place in your code!
I hope this helps.