I was playing with C/'s fopen() and putc() functions and wanted to implement serialization/deserialization of a structure. However, here some "Segmentation fault" error occurs. I investigated similar questions and found, that it happens when I am trying to access some memory that doesn't belong to me.
What should I fix in my code to make it work properly?
struct Account {
string holder_name;
string holder_password;
double current_sum;
};
int save_to_file(Account * account);
Account * load_from_file(string holder_name);
int main(){
Account account = { "BEN", "password", 200.0 };
save_to_file(&account);
load_from_file("BEN");
return 0;
}
int save_to_file(Account * account){
const char * cstr = account->holder_name.c_str();
int size = sizeof(struct Account);
FILE * fp = fopen(cstr, "wb");
char * c;
c = (char *) account;
for(int i=0; i < size; i++)
{
putc(*c++, fp);
}
return fclose(fp);
}
Account * load_from_file(string holder_name)
{
FILE * fp;
char *c;
int i;
int size = sizeof(struct Account);
struct Account * ptr = (struct Account *) malloc(sizeof(struct Account));
if ((fp = fopen(holder_name.c_str(), "rb")) == NULL)
{
perror("Error occured while opening file");
return NULL;
}
c = (char *)ptr;
while ((i = getc(fp))!=EOF)
{
*c = i;
c++;
}
fclose(fp);
return ptr;
}
The string type doesn't belongs to C language, it's a object that comes from C++.
Since it may be implemented with pointers inside the object, you can't simply write their binary values to a file : the pointed memory won't be allocated when you'll read the file later.
A simple rule is that writing a pointer value to a file is a probably a mistake.
For your code to work, simply replace the string type with a char []. Here is the code with this only modification :
#include <stdlib.h>
#include <stdio.h>
struct Account {
char holder_name[100];
char holder_password[100];
double current_sum;
};
int save_to_file(struct Account * account);
struct Account * load_from_file(char *holder_name);
int main(){
struct Account account = { "BEN", "password", 200.0 };
save_to_file(&account);
load_from_file("BEN");
return 0;
}
int save_to_file(struct Account * account){
const char * cstr = account->holder_name;
int size = sizeof(struct Account);
FILE * fp = fopen(cstr, "wb");
char * c;
c = (char *) account;
for(int i=0; i < size; i++)
{
putc(*c++, fp);
}
return fclose(fp);
}
struct Account * load_from_file(char *holder_name)
{
FILE * fp;
char *c;
int i;
int size = sizeof(struct Account);
struct Account * ptr = (struct Account *) malloc(sizeof(struct Account));
if ((fp = fopen(holder_name, "rb")) == NULL)
{
perror("Error occured while opening file");
return NULL;
}
c = (char *)ptr;
while ((i = getc(fp))!=EOF)
{
*c = i;
c++;
}
fclose(fp);
return ptr;
}
Related
I can not get my c++ application to work properly, i will paste my simple memory class and a test app here.
Right now i get an access violation and no output when i run it in the console. I use Visual Studio 2015.
I seem to haave problems with my car class, not sure what could be wrong. And i ge some error message if i try to debug. I have no idea how to fix it...
#define WIN32_LEAN_AND_MEAN
enum memtype {typechar = 1, typeint};
class Mem
{
public:
Mem(int size);
void * alloc(memtype t);
void * ptr();
void release();
~Mem();
private:
int sizebytes;
void * p;
};
#include <new.h>
#include "Mem.h"
Mem::Mem(int size)
{
sizebytes = size;
}
void * Mem::alloc(memtype t)
{
if (t==typechar)
{
p = (char *)new char(sizebytes);
return p;
}
}
void * Mem::ptr()
{
return p;
}
void Mem::release()
{
if(p)
delete p;
}
Mem::~Mem()
{
if(p)
delete p;
}
#include "Mem.h"
#include <stdio.h>
int check(void * p)
{
int retval = 0;
if (p == NULL)
{
printf("Memory Fail: NULL pointer...\n");
retval = 0;
}
else
retval = 1;
return retval;
}
class Car
{
public:
Car::Car()
{
Car::name = 0;
Car::brand = 0;
Car::type = 0;
}
int Car::alloc(char *inname, char *inbrand, char *intype)
{
Car::name = new Mem(sizeof(*inname));
if (!check(Car::name->alloc(typechar)))
return 0;
printf("%s", sizeof(*inname));
Car::brand = new Mem(sizeof(*inbrand));
if (!check(Car::brand->alloc(typechar)))
return 0;
printf("%s", sizeof(*inbrand));
Car::type = new Mem(sizeof(*intype));
if (!check(Car::type->alloc(typechar)))
return 0;
printf("%s", sizeof(*intype));
/*sprintf?*/
sprintf_s((char *)Car::name->ptr(), sizeof(*inname), "%s", inname);
sprintf_s((char *)Car::brand->ptr(), sizeof(*inbrand), "%s", inbrand);
sprintf_s((char *)Car::type->ptr(), sizeof(*intype), "%s", intype);
return 1;
}
char * Car::getName()
{
if(Car::name!=0)
return (char *)Car::name->ptr();
}
char * Car::getBrand()
{
if(Car::brand!=0)
return (char *)Car::brand->ptr();
}
char * Car::getType()
{
if(Car::type!=0)
return (char *)Car::type->ptr();
}
Car::~Car()
{
if (Car::name != 0)
delete Car::name;
if (Car::brand != 0)
delete Car::brand;
if (Car::type != 0)
delete Car::type;
}
private:
Mem *name, *brand, *type;
};
void store()
{
}
int main()
{
Mem cartype1(sizeof("Sedan"));
cartype1.alloc(typechar);
check(cartype1.ptr());
Mem cartype2(sizeof("Van"));
cartype2.alloc(typechar);
check(cartype2.ptr());
Mem cartype3(sizeof("Pickup"));
cartype3.alloc(typechar);
check(cartype3.ptr());
sprintf((char *)cartype1.ptr(), "%s", "Sedan");
sprintf((char *)cartype2.ptr(), "%s", "Van");
sprintf((char *)cartype3.ptr(), "%s", "Pickup");
Mem carname(sizeof("Supah Car"));
carname.alloc(typechar);
check(carname.ptr());
Mem carbrand(sizeof("Supah"));
carbrand.alloc(typechar);
check(carbrand.ptr());
sprintf((char *)carname.ptr(), "%s", "Supah Car");
sprintf((char *)carbrand.ptr(), "%s", "Supah");
Car test;
test.alloc((char *)carname.ptr(), (char *)carbrand.ptr(), (char *)cartype1.ptr());
printf("%s is of brand %s and type %s\n", test.getName(), test.getBrand(), test.getType());
char * nullptrtest = NULL;
printf_s("%d", &test);
printf_s("sizeof int %d\n", sizeof(int));
printf_s("Test %s\n", carname.ptr());
return 1;
}
int Car::alloc(char *inname, char *inbrand, char *intype)
{
Car::name = new Mem(sizeof(*inname));
sizeof *inname will give you sizeof(char) == 1
So your name member has allocated array of 1 char exactly.
You later write to this array a lot more. As a result your heap is corrupted.
I do not know why you want to play with emulating memory allocation instead of using std::string - but you need to allocate at least strlen(inname)+1 bytes to store inname
I am attempting to create a program to create a Markov chain but I am having pointer problems. When I run the Program I get a segmentation fault.
#include <stdio.h>
#include <cstring>
#include <cstdlib>
struct word;
struct nextword
{
word* sourceword;
word* next = 0;
};
int wordcount;
struct word
{
char* wordstr;
struct word* next = 0;
nextword* followingword = 0;
int nextwordcount = 0;
};
int main()
{
word* firstword = 0;
char * buffer = 0;
long length;
FILE * f = fopen ("alice.txt", "rb");
if (f)
{
fseek (f, 0, SEEK_END);
length = ftell (f);
fseek (f, 0, SEEK_SET);
buffer = (char *)malloc (length);
if (buffer)
{
fread (buffer, 1, length, f);
}
fclose (f);
}
if (buffer)
{
char wordbuffer[500];
int fileindex = 0;
while(fileindex < length-1)
{
int wordindex = 0;
while(buffer[fileindex] != ' ')
{
wordbuffer[wordindex] = buffer[fileindex];
wordindex++;
fileindex++;
}
if(wordindex != 0)
{
wordbuffer[wordindex] = '\0';
word* newword = (word*)malloc(sizeof(word));
char* newwordstr = (char*)malloc((strlen(wordbuffer)+1)*sizeof(char));
strcpy(newword->wordstr, newwordstr);
if(!firstword)
{
firstword = newword;
}
else
{
word* testword = firstword;
while(!testword->next)
{
testword = (testword->next);
}
testword->next = newword;
printf(newword->wordstr);
}
}
return 0;
}
}
else
{
return 1;
}
}
I attempted to remove the file reading part and replace it with a hard coded string, but the problem remained.
You might want to read about STL and use a list. Or use a C list, see a couple of examples,
Adding node in front of linklist
How to pop element from tail in linked list?
Trying to make linkedlist in C
Several problems. Fixed some. compiles.
I have annotated the code with places where you need to fix bounds checking, and the big problem was likely the strcpy to the struct word->wordstr uninitialized char*,
#include <stdio.h>
#include <cstring>
#include <cstdlib>
struct word;
struct nextword
{
word* sourceword;
word* next = 0;
};
int wordcount;
struct word
{
char* wordstr; //what do you think this pointer points to?
struct word* next = 0;
nextword* followingword = 0;
int nextwordcount = 0;
};
int main()
{
FILE* fh = NULL;
word* firstword = 0;
char* buffer = 0;
char* fname = "alice.txt";
long length = 0; //you did not initialize length
if ( (fh = fopen ("alice.txt", "rb")) )
{
//why not use fstat to get file size?
//why not use mmap to read file?
fseek (fh, 0, SEEK_END);
length = ftell (fh); //ok, length set here
fseek (fh, 0, SEEK_SET);
if( (buffer = (char *)malloc (length)) )
{
fread (buffer, 1, length, fh);
}
fclose (fh);
}
else
{
printf("error: cannot open %s",fname);
exit(1);
}
printf("read %s, %ld\n",fname,length);
if (!buffer)
{
printf("error: cannot open %s",fname);
exit(1);
//use exit, to return from main() //return 1;
}
//already checked buffer
{
int fileindex = 0;
//put wordbuffer after fileindex, avoids stackoverflow overwrite
char wordbuffer[500]; //500 bytes on stack, initialize?
memset(wordbuffer,0,sizeof(wordbuffer));
while(fileindex < length-1)
{
int wordindex = 0;
//several errors in this line, check for null terminator,
//check for newline, tab, basically any whitespace
//while(buffer[fileindex] != ' ')
while( buffer[fileindex] && buffer[fileindex] != ' ' )
{
wordbuffer[wordindex] = buffer[fileindex];
wordindex++;
fileindex++;
//here is another error, do not overflow your stack based buffer
if( wordindex>sizeof(buffer)-1 ) break; //do not overflow buffer
}
wordbuffer[wordindex] = '\0'; //terminate wordbuffer
//since you chose wordindex signed, you want it > 0
if(wordindex > 0)
{
//use a constructor
word* newword = (word*)malloc(sizeof(word));
//use a constructor
//or just use strdup, since it is just a cstring
char* newwordstr = strdup(wordbuffer);
//no, just set pointer to the above allocated string
//strcpy(newword->wordstr, newwordstr);
newword->wordstr = newwordstr;
if(!firstword)
{
firstword = newword;
}
else
{
word* testword = firstword;
while(!testword->next)
{
testword = (testword->next);
}
testword->next = newword;
printf(newword->wordstr);
}
}
return 0;
}
}
exit(0); //done
}
This compiles and runs without error, you need to look up linked list handling. You should implement a linked list, and then add word elements to list.
Since i am quiet new to C++ and Image processing i have a problem modifying and adding a function to the code.
The requirement is only to switch between the RGB colors.
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "ctype.h"
#include "math.h"
class myImageData
{
private:
int mW;
int mH;
int mCH;
double * mData;
void SkipComments(FILE *fp)
{
int ch;
char line[100];
while ((ch = fgetc(fp)) != EOF && isspace(ch))
;
if (ch == '#')
{
fgets(line, sizeof(line), fp);
SkipComments(fp);
}
else
{
fseek(fp, -1, SEEK_CUR);
}
}
public:
myImageData(void)
{
this->mData = NULL;
}
~myImageData()
{
if (this->mData != NULL)
{
delete[] this->mData;
}
}
void init(int W, int H, int CH)
{
this->mW = W;
this->mH = H;
this->mCH = CH;
if (this->mData != NULL)
delete[] this->mData;
this->mData = new double[(this->mW)*(this->mH)*(this->mCH)];
}
int getWidth(void)
{
return this->mW;
}
int getHeight(void)
{
return this->mH;
}
int getCH(void)
{
return this->mCH;
}
double * getDataPtr(void)
{
return this->mData;
}
double get(int x, int y)
{
return this->mData[y*(this->mW) + x];
}
double get(int x, int y, int CH)
{
return this->mData[this->mCH * (y*(this->mW) + x) + CH];
}
void set(int x, int y, double value)
{
this->mData[y*(this->mW) + x] = value;
}
void set(int x, int y, int CH, double value)
{
this->mData[this->mCH *(y*(this->mW) + x) + CH] = value;
}
void read(const char *filename);
void save(const char *filename);
};
void myImageData::read(const char *filename)
{
FILE *file = fopen(filename, "r");
if (file == NULL){
printf("Cannot open %s\n", filename);
exit(1); //abnormal termination
}
printf("Read an image from: %s\n", filename);
// read ppm/pgm header
char buf[256];
char filetype[256];
int W, H, Range, CH;
fgets(buf, sizeof(buf), file);
sscanf(buf, "%s", filetype);
SkipComments(file);
fgets(buf, sizeof(buf), file);
sscanf(buf, "%d%d", &W, &H);
SkipComments(file);
fgets(buf, sizeof(buf), file);
sscanf(buf, "%d", &Range);
//printf("Header: %s, %d, %d, %d\n", filetype, W, H, Range);
SkipComments(file);
if (strcmp(filetype, "P5") == 0)
{
CH = 1;
}
else if (strcmp(filetype, "P6") == 0)
{
CH = 3;
}
else
{
printf("Unknown image type\n");
exit(1); //abnormal termination
}
if (Range != 255){
printf("Invalid data\n");
exit(1); //abnormal termination
}
// create myImageData class
init(W, H, CH);
// read ppm data
int datalength = this->mW * this->mH * this->mCH;
unsigned char * temp = new unsigned char[datalength];
fread(temp, sizeof(unsigned char), datalength, file);
double * ptr1 = this->mData;
unsigned char *ptr2 = temp;
for (int i = 0; i < datalength; i++){
*ptr1 = (double)*ptr2;
ptr1++;
ptr2++;
}
delete[] temp;
fclose(file);
}
void myImageData::save(const char *filename){
char filenamefull[256];
if (this->mCH == 1){
sprintf(filenamefull, "%s.pgm", filename);
}
else{
sprintf(filenamefull, "%s.ppm", filename);
}
FILE *file = fopen(filenamefull, "w");
printf("Write an image to: %s \n", filenamefull);
if (this->mCH == 1){
fprintf(file, "P5\n");
}
else{
fprintf(file, "P6\n");
}
fprintf(file, "%d %d\n", this->mW, this->mH);
fprintf(file, "255\n");
int datalength = this->mW * this->mH * this->mCH;
unsigned char * temp = new unsigned char[datalength];
double * ptr1 = this->mData;
unsigned char * ptr2 = temp;
for (int i = 0; i < datalength; i++){
double value = *ptr1;
value = round(value);
if (value > 255) value = 255;
if (value < 0) value = 0;
*ptr2 = (unsigned char)value;
ptr1++;
ptr2++;
}
fwrite(temp, sizeof(unsigned char), datalength, file);
delete[] temp;
fprintf(file, "Â¥n");
fclose(file);
}
The errors i am having:
error LNK2019: unresolved external symbol _main referenced in function ___tmainCRTStartup
error LNK1120: 1 unresolved externals
Firstly, you have no main function. No surprise that your code doesn't work.. all you have is a class to load, save and manipulate PPM image files.
You appear to me using Visual Studio, so you'll need a function that looks like this:
int _tmain(int argc, _TCHAR* argv[])
{
myImageData image;
image.read("atestfile.ppm");
// do some stuff to your image
image.write("outputfile.ppm");
}
I'm assuming you have a test image in PPM format you can use here, of course.
Now this is madness:
double * ptr1 = this->mData;
unsigned char * ptr2 = temp;
for (int i = 0; i < datalength; i++){
double value = *ptr1;
value = round(value);
if (value > 255) value = 255;
if (value < 0) value = 0;
*ptr2 = (unsigned char)value;
ptr1++;
ptr2++;
}
You've read from an unsigned char, so there's no point stuffing it into a double, and there's definitely no point in checking if the value lies outside of 0 to 255. Why are you storing things in doubles? It makes no sense! Even if you did do something that needed a full double-precision floating point value per channel, you throw it all away in the output when you clamp everything to 0-255 again:
for (int i = 0; i < datalength; i++){
double value = *ptr1;
value = round(value);
if (value > 255) value = 255;
if (value < 0) value = 0;
*ptr2 = (unsigned char)value;
ptr1++;
ptr2++;
}
Also, this is basically C dressed up in a thin C++ veneer. That's okay, everyone has to start somewhere. But instead of using new to create an array, you can do this:
// read ppm data
int datalength = this->mW * this->mH * this->mCH;
// using a std::vector here means that the allocated memory will be freed
// automatically, even in the result of an error occurring.
std::vector<unsigned char> temp(datalength);
fread(&temp[0], sizeof(unsigned char), datalength, file);
I'd also consider using iostream classes such as fstream instead of fread and fopen and so on. But this is not really the place to get into those kinds of details.
Anyway, What to do with your image once it is loaded? You've got dead easy helper functions to read and write pixel values, which will let you do pretty much anything you want. Here's a simple example, swapping the R and B channels. You might get something better when you actually tell us what you wanted.
void swapRB(myImageData& image)
{
assert(image.getCH() == 3);
for (int x = 0; x < image.getWidth())
{
for (int y = 0; x < image.getHeight())
{
double R = image.get(x, y, 0);
double G = image.get(x, y, 1);
double B = image.get(x, y, 2);
image.set(x, y, 0, B);
image.set(x, y, 2, R);
}
}
}
i have this function to get the content of file ,
#define BUFSIZE 512
vector<int> getContFile(char* pFile) {
ifstream vCin(pFile, ios::binary);
ifstream::pos_type size;
// get vLength of file:
vCin.seekg(0, ios::end);
size = vCin.tellg();
vCin.seekg(0, ios::beg);
vector<int> vTmp;
for (int i = 0; i < size; i++)
vTmp.push_back(vCin.get());
vCin.close();
return vTmp;
}
and this to send to the server
void SendFile() {
SendS("upFileUser");
int i;
vector<int> vTmp = getContFile("/usr/home/alex/Desktop/eval.tar");
for (i = 0; i < vTmp.size(); i += BUFSIZE) {
char *vBuff = new char[BUFSIZE];
for (int j = i; j < BUFSIZE; j++)
vBuff[j] = (char(vTmp[i]));
SendS(vBuff);
}
if (i < (vTmp.size() - 1)) {
char *vBuff = new char[vTmp.size() - i];
for (int j = 0; j < vTmp.size() - i; j++)
vBuff[j + i] = (char(vTmp[j + i]));
SendS(vBuff);
}
sendS("endOfFileTransmision");
}
void SendS(char* pSir) {
int vLen = strlen(pSir);
write(pSocket, &vLen, sizeof (int));
write(pSocket, pSir, vLen);
}
this is the receve function
char* reciveS() {
char* vTmp;
int vCt = 0;
read(pSocket, &vCt, sizeof (vCt));
if (vCt != 0) {
vTmp = new char[vCt];
read(vSocket, vTmp, vCt);
} else {
vTmp = NULL;
}
return vTmp;
}
bool receveFile(void) {
char* vReceve = reciveS();
if (strcmp(vReceve, "upFileUser") == 0)
{
ofstream vCoutFile;
vCoutFile.open("data2.tar", ios::out | ios::binary);
while (true) {
char *vTmp = new char[BUFSIZ];
vTmp = reciveS();
cout<<vTmp;
if (strcmp(vTmp, "endOfFileTransmision") == 0) break;
else {
cout << vTmp;
vCoutFile << vTmp;
}
}
vCoutFile.close();
}
}
and the result are a broke pipe(i run this to freebsd 6.4 amd with g++ compiler) , so what i miss , the connection are good i can transfer text from client to server and reverse the problem are with binary file
I see two problems with your code:
You are making a lot of allocations (new) but you never free the memory.
In the SendS function you are taking the string length, but the data in that "string" is from a vector of integers and is binary. This means that the data can contain the string-terminating '\0' character (the integer 0).
Besides that, I really don't follow what you are doing. Instead of reading into a vector, create a char-buffer and allocate enough memory to put the whole file into that buffer (char *buffer = new char[length_of_file]) and send it, with the length of the buffer first.
Something like this:
std::pair<size_t, char *> getContFile(const char *pFile)
{
ifstream vCin(pFile, ios::binary);
ifstream::pos_type size;
vCin.seekg(0, ios::end);
size = vCin.tellg();
vCin.seekg(0, ios::beg);
char *buffer = new char[size];
vCin.read(buffer, size);
return std::make_pair(static_cast<size_t>(size), buffer);
}
void SendFile()
{
SendS("upFileUser", strlen("upFileUser"));
std::pair<size_t, char *> vTmp = getContFile("/usr/home/alex/Desktop/eval.tar");
SendS(vTmp.second, vTmp.first);
delete [] vTmp.second;
}
void SendS(char *buffer, size_t length)
{
// Send the length
size_t tmp = htonl(length);
write(pSocket, &tmp, sizeof(tmp));
// Send the buffer
while (length > 0)
{
ssize_t sent = write(pSocket, buffer, length);
if (sent <= 0)
{
// Some kind of error
break;
}
buffer += sent;
length -= sent;
}
}
Do something similar on the receiving side.
Updated code: 3/7/11 : 9:29pm
using namespace std;
void * matrixACreate(void * param);
void *status;
struct a
{
int Arow; // Matrix A
int Acol; // WxX
int low; // Range low
int high;
};
int main(int argc, char * argv[])
{
struct a matrix_mult_info;
matrix_mult_info.Arow = atoi(argv[1]); // Matrix A
matrix_mult_info.Acol = atoi(argv[2]); // WxX
matrix_mult_info.low = atoi(argv[5]); // Range low
matrix_mult_info.high = atoi(argv[6]);
pthread_t matrixAthread;
pthread_t runner;
int error, retValue;
struct a * a = (struct a *) malloc(sizeof(struct a));
error = pthread_create(&matrixAthread, NULL, matrixACreate, a );
//error = pthread_create(&matrixAthread, NULL, matrixBCreate, sendB);
retValue = pthread_join(matrixAthread, &status);
//retValue = pthread_join(matrixBthread, &status);
return 0;
}
void * matrixACreate(void * param) {
struct a * matrix = (struct a *) param;
int range = ((matrix->high - matrix->low) + 1);
cout << matrix->Arow << endl;
return 0;
}
struct a * a = (struct a *) malloc(sizeof(struct a));
// init a's members
error = pthread_create(&matrixAthread, NULL, matrixACreate, a);
EDIT: In response to updated question:
void * matrixACreate(void * param) {
struct a * matrix = (struct a *) param;
int range = ((matrix->high - matrix->low) + 1);
cout << matrix->Arow << endl;
return NULL;
}