Reputation: 121
I'm using SFML's TcpSocket
class to send and receive data, but for some reason I keep getting the error Segmentation fault: 11
. Here's the server class:
#include "ServerGame.hpp"
ServerGame::ServerGame()
{
}
void ServerGame::sendData(char data[3][3])
{
if (client.send(data, 9) != sf::Socket::Done)
{
//std::cout << "error" << std::endl;
}
}
void ServerGame::connect()
{
sf::TcpListener listener;
// bind the listener to a port
if (listener.listen(666) != sf::Socket::Done)
{
std::cout << "error" << std::endl;
}
// accept a new connection
if (listener.accept(client) != sf::Socket::Done)
{
std::cout << "error" << std::endl;
}
}
char** ServerGame::receiveData()
{
char **data;
data = new char*[3];
for(int i = 0; i < 3; ++i)
{
data[i] = new char[3];
}
std::size_t received;
// TCP socket:
if (client.receive(data, 9, received) != sf::Socket::Done)
{
// error...
}
return data;
}
Here's the client class:
#include "ClientGame.hpp"
#include <iostream>
ClientGame::ClientGame()
{
}
void ClientGame::connect()
{
sf::Socket::Status status = socket.connect("127.0.0.1", 666);
if (status != sf::Socket::Done)
{
// error...
}
}
void ClientGame::sendData(char data[3][3])
{
if(socket.send(data, 9) != sf::Socket::Done)
{
//error...
}
}
char** ClientGame::receiveData()
{
char **data;
data = new char*[3];
for(int i = 0; i < 3; ++i)
{
data[i] = new char[3];
}
std::size_t received;
if (socket.receive(data, 9, received) != sf::Socket::Done)
{
std::cout << "error" << std::endl;
}
return data;
}
This is the main class that starts the server and sends data:
#include "ServerGame.hpp"
#include "ClientGame.hpp"
int main()
{
ServerGame sg;
sg.connect();
char arr[3][3] =
{
{'a', 'b', 'c'},
{'d', 'e', 'f'},
{'g', 'h', 'i'}
};
sg.sendData(arr);
}
This is the main class that starts the client and receives data:
#include "ClientGame.hpp"
int main()
{
ClientGame cg;
cg.connect();
char** arr = cg.receiveData();
std:: cout << arr[0][0] << std::endl;
}
I first compile and run the server class, and then do the same with the client class. When I try to access the first element of the character array I send, it gives a segmentation fault. Why is this happening?
Upvotes: 0
Views: 212
Reputation: 35454
One issue is assuming that char**
is the same as a two dimensional array of char
. They are not the same.
When you do this:
char **data;
data = new char*[3];
for(int i = 0; i < 3; ++i)
{
data[i] = new char[3];
}
you are not creating a two-dimensional char
array dynamically with a contiguous data layout, similar to a char[3][3]
. The memory layout could look something like this:
data[0] -> 0x32181000
data[1] -> 0x321A9760
data[2] -> 0x321AC980
In other words, the rows are strewn all over the heap memory, and are not contiguous.
Thus when you call this function:
if (socket.receive(data, 9, received) != sf::Socket::Done)
the socket.receive
function is expecting a contiguous buffer of 9 bytes, but you are not providing this. The receive
function more than likely overwrites the first row with up to 6 bytes falling off the edge of the first row (the first row is allocated to only have 3 bytes), and thus spilling over into memory that causes the segmentation fault.
I think the issue stems from you trying to pass a two-dimensional array around from function to function, and making mistakes by using char**
in lieu of an actual 2 dimensional array.
To make things easier without having to introduce pointers, create a struct
that contains a 2-dimensional char
array, and then pass this struct between the functions.
struct char2D
{
char myArray[3][3];
};
Then instead of char **
, just use an instance of char2D
, and refer to the inner array when you need to.
For example:
char2D ClientGame::receiveData()
{
char2D data;
std::size_t received;
if (socket.receive(&data.myArray[0][0], 9, received) != sf::Socket::Done)
{
std::cout << "error" << std::endl;
}
return data;
}
Then in main
:
int main()
{
ClientGame cg;
cg.connect();
char2D arr = cg.receiveData();
std:: cout << arr.myArray[0][0] << std::endl;
}
The reason why this works is that a struct
is copyable and assignable. So the inner array gets copied whenever you pass it by value and return it by value.
Upvotes: 2