Hello I'm trying to read/write my own file formats to learn about c++. I've figured out the reading and writing part with fstream so far, but when extracting my code into seperate functions I've ran into some trouble.
Maybe it's my expectations that are wrong, but here is how I intended to handle it.
Main Function
int main()
{
const char* path = "path/to/file.dat";
// this pointer should be changed to the pointer referencing the heap(?) allocated
// buffer inside the function 'readFromFile'
char* buffer;
// How can I pass the buffer in a way that sets the pointer to the buffer in
// this scope to the pointer that is created and allocated inside this function?
int bufferSize = readFromFile(path, buffer);
// log colour data to console
for (int i = 0; i < bufferSize; i += 4)
{
std::cout << "rgba("
<< buffer[i] << ", "
<< buffer[i + 1] << ", "
<< buffer[i + 2] << ", "
<< buffer[i + 3] << ")" << std::endl;
}
}
ReadFromFile Function
// also tried 'char* &buffer'
int readFromFile(const char* path, char* buffer)
}
// read and parse the file header...
// this contains the rgba data size
// allocate data for the buffer based on the header information
buffer = new char[header.DataLength];
// fill the buffer with data from the file
fs.read(buffer, header.DataLength);
// reading is sucessful
// buffer in this scope is filled
return header.DataLength;
}
Two ways I found to pass a pointer by reference are:
char* buffer;
readFromFile(x, &buffer);
int readFromFile(x, char** buffer);
readFromFile(x, buffer);
int readFromFile(x, char* &buffer); //is what I ended up going with
I'm quite new to c++ so memory management and pointers are fairly foreign concepts to me. I'm pretty sure my problem is a standard one, but I haven't been able to figure out how to do it yet. If anyone could point me in the right direction it would be greatly appreciated. Thanks in advance.
The pseudo-code I ended up writing was correct as #molbdnilo pointed out, but in my actual project I accidentally mixed both the aproaches.
old code:
char* buffer;
readFromFile(x, &buffer);
int readFromFile(x, char*& buffer);
which my compiler responded to with: initial value of reference to non-const must be an lvalue
Check the last code block in my question to see what ended up working.
Thanks for the quick replies everyone!
Related
I am trying to get the various attributes of a file as seen in its "Details" tab with the WinAPI function VerQueryValue. I have successfully used this function to get the non-string version info with VS_FIXEDFILEINFO, but have not been able to get the example shown at the bottom of the functions documentation working.
The example isn't actually complete as it leaves out the use of the other related functions and the constructions of some buffers needed to use the function, so I've filled in the blanks the best I can and changed some of the in-between steps to use C++ SL since that's ultimately the language I need to use this in:
#include <iostream>
#include <iomanip>
#include "sstream"
#include "Windows.h"
#pragma comment(lib, "Version.lib")
int ReadOutFileDescriptions(std::wstring filename)
{
LPBYTE lpBuffer = NULL;
DWORD verHandle, verSize = GetFileVersionInfoSize(filename.c_str(), &verHandle);
if (verSize != NULL)
{
LPSTR verData = new char[verSize];
if (GetFileVersionInfo(filename.c_str(), verHandle, verSize, verData))
{
UINT cbTranslate;
// Structure used to store enumerated languages and code pages.
struct LANGANDCODEPAGE {
WORD wLanguage;
WORD wCodePage;
} *lpTranslate;
// Read the list of languages and code pages.
VerQueryValue(verData, TEXT("\\VarFileInfo\\Translation"), (LPVOID*)&lpTranslate, &cbTranslate);
// Read the file description for each language and code page.
for (ULONGLONG i = 0; i < (cbTranslate / sizeof(struct LANGANDCODEPAGE)); i++)
{
std::wostringstream ss; ss << std::setfill(L'0') << std::hex;
ss << std::setw(4) << lpTranslate[i].wLanguage;
std::wstring langS = ss.str();
ss.str(std::wstring());
ss << std::setw(4) << lpTranslate[i].wCodePage;
std::wstring codeS = ss.str();
std::wstring subBlock = L"\\StringFileInfo\\" + langS + codeS + L"\\FileDescription";
// Retrieve file description for language and code page "i".
WCHAR descBuffer[50];
LPVOID lpBuffer = &descBuffer;
UINT bufferSize;
VerQueryValue(verData, subBlock.c_str(), &lpBuffer, &bufferSize);
std::cout << bufferSize << '\n' << descBuffer;
}
}
delete[] verData;
}
return 0;
}
int main(int argc, char* argv[])
{
ReadOutFileDescriptions(L"MyFile.exe");
return 0;
}
I only have a little experience with WinAPI and its typedefs and my C is a bit rusty so I'm sure I'm just setting-up/using a buffer incorrectly or the like.
The printed buffer size is correct (the length of MyFile.exe's description + 1 for the null character) so I know the function is getting the right value, but the actually value that gets printed is just a series of hexadecimal character, most likely an address.
What am I doing wrong?
EDIT (Answer):
Thanks to #dxiv I was made aware that I did not fully understand how the "result" argument (lplpBuffer) of VerQueryValue was to be used, both internally and after the function returns.
Changing the end of the loop to the following achieves my desired result:
//WCHAR descBuffer[50] Not required, the function doesn't utilize a user made buffer
LPVOID lpBuffer;
UINT bufferSize;
VerQueryValue(verData, subBlock.c_str(), &lpBuffer, &bufferSize); // lpBuffer is reassigned here
std::wstring fileDescription((const TCHAR*)lpBuffer); // Create std::string from C style string (char*) that lpBuffer now points to
std::wcout << bufferSize << '\n' << fileDescription;
VerQueryValue(verData, subBlock.c_str(), &lpBuffer, &bufferSize);
std::cout << bufferSize << '\n' << descBuffer;
Once VerQueryValue returns, lpBuffer no longer points to descBuffer, but to a different buffer assigned inside the call. The returned string is at (const TCHAR *)lpBuffer at that point.
My program use a small SQLite3 database. To make sure it actually exist when the program is launched, I have a database creation script in a file, that is executed.
The script work without problem.
However, when using C++ I/O functions to read from that file, I am getting really often invalid characters at the end of my file, which result in the script containing errors and not being properly executed by the SQLite library. Here is an example when displaying the buffer content:
// Proper content from the file, then a random character is there
1
Error executing request: near "1": syntax error
Other characters also appear, whitespaces, numbers, letters...
Here is the code where I load my script :
std::cerr << "Creating database if needed...\n";
char sql_script[] = "/path/to/script.sql";
int script_length;
bool result = false;
std::ifstream script_fs(sql_script, std::fstream::binary | std::fstream::in);
if (script_fs) {
char* buffer;
char** err_msg = NULL;
script_fs.seekg(0, script_fs.end);
script_length = script_fs.tellg();
script_fs.seekg(0, script_fs.beg);
buffer = new char[script_length];
script_fs.read(buffer, script_length);
std::cout << "sql:\n" << buffer << "\n";
if (sqlite3_exec(m_db, buffer, NULL, NULL, err_msg) == SQLITE_OK){
result = true;
} else {
std::cerr << "Error executing: " << sqlite3_errmsg(m_db) << "\n" << err_msg << "\n";
}
delete buffer;
script_fs.close();
} else {
std::cerr << "Error opening script: " << strerror(errno) << "\n";
}
return result;
}
Why is this happening and how can I fix this ?
You need to make sure that you have a null-terminated string.
Allocate memory for one more character.
Assign the null character to the last element of buffer.
buffer = new char[script_length+1];
script_fs.read(buffer, script_length);
buffer[script_length] = '\0';
Also, use the array form of delete.
delete [] buffer;
Don't mix C and C++, If you want to read sql query file in C++ using ifstream then below code in C++ can be one approach in which you don't need to manage memory, take care of things like allocating one extra char of '\0' etc. :
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
int main() {
ifstream fin("test.sql", std::fstream::binary | std::fstream::in);
std::string sqlquery = std::string(std::istreambuf_iterator<char>(fin), std::istreambuf_iterator<char>());
std::cout<<sqlquery<<std::endl;
return 0;
}
I am currently writing a socket wrapper in C++ for Linux. It is basically a collection of classes that handle the creation, connection, sending, reading, and closing of a TCP socket.
In my socket class, all functions work well except for the send and receive function. They do not return an error; instead, it only sends the first four bytes of data.
My send function:
int Socket::sends(char* buffer){
int bytes; // for number of bytes sent
/* First, send the size of buffer */
int datalen = strlen(buffer); // get sizeof buffer
int len = htonl(datalen); // reformat
// send the size of the buffer
bytes = send(socketfd, (char*)&len, sizeof(len), 0); // send the size
if (bytes < 0){
cerr << "Error sending size of buffer to socket" << endl;
return 1;
}
/* Now acutally send the data */
bytes = send(socketfd, buffer, datalen, 0);
if (bytes < 0){
cerr << "Error writing buffer to socket" << endl;
return 1;
}
cout << bytes << " written" << endl;
return 0;
}
The ideas behind it is that It sends the buffer (char* buffer) by first sending the size of the buffer, and then sending the actual buffer. If an error is encountered (returning -1) the function terminates by returning 1.
Now, here is the read method:
int Socket::reads(char* buffer){
int bytes, buflen; // for bytes written and size of buffer
/* Read the incoming size */
bytes = recv(socketfd, (char*)&buflen, sizeof(buflen), 0);
if (bytes < 0){
cerr << "Error reading size of data" << endl;
return 1;
}
buflen = ntohl(buflen);
/* Read the data */
bytes = recv(socketfd, buffer, buflen, 0);
if (bytes < 0){
cerr << "Error reading data" << endl;
return 1;
}
return 0;
}
Here, the idea is to read the size of the data first, and then set the buffer to that size and read into it. The function returns 1 on error (recv returns -1).
Using the methods would look something like this:
socket.sends("Hello World"); // socket object sends the message
char* buffer;
socket.reads(buffer); // reads into the buffer
However, when ever I use these functions, I only receive the first 4 bytes of data, followed by strange, non-ASCII characters. I have no idea why this happens. No error is not encountered in the send and recv functions, and the functions say that only 4 bytes were written. Is there a better way that I should send or receive data? I am overlooking a very simple error?
Thanks for your help!
you're passing an uninitialized pointer (buffer) to your reads method, which probably explains that it works partially (undefined behaviour).
And you shouldn't pass buffer as a parameter since it won't be modified (and you don't know the size yet anyway)
Plus, you have to null-terminate your message when you recieve it.
I would do like this:
char *Socket::reads(){
char* buffer;
int bytes, buflen; // for bytes written and size of buffer
/* Read the incoming size */
bytes = recv(socketfd, (char*)&buflen, sizeof(buflen), 0);
if (bytes < 0){
cerr << "Error reading size of data" << endl;
return 1;
}
buflen = ntohl(buflen);
buffer = new char[buflen+1]; // +1 for the NUL-terminator
/* Read the data */
bytes = recv(socketfd, buffer, buflen, 0);
if (bytes < 0){
cerr << "Error reading data" << endl;
return 1;
}
buffer[buflen] = '\0'; // NUL-terminate the string
return buffer;
}
the main:
socket.sends("Hello World"); // socket object sends the message
char* buffer = socket.reads(); // reads into the buffer
don't forget to delete [] the buffer in the end.
Could also be done with std::string or std::vector<char> to avoid new and delete
Pardon my absolute lack of any understanding here, just diving into C++. So essentially I just wanted to see if I could figure out how to use putc to properly write characters to a file. I wanna make sure I'm understanding every step of the way.
Now, when looking at the address spaces used when I originally declared the pointer for the file, and after passing the pointer to a different function that would write the stream to a file I noticed the address spaces are completely different, even in length, than that of the address space of the original function. Still trying to completely wrap my head around pointers but it's hard without any intervention to tell you where you are misinterpretting things, and I know I have to be. Here is the code, dont mind the fact I'm doing it in Qtcreator. Links help but please don't just copy pasta some C++ info page on pointers. I've read it.
#include <QCoreApplication>
#include <stdio.h>
#include <iostream>
#include <fstream>
using namespace std;
void stream_writer(FILE & stream)
{
int c1='A',
c2='B',
c3='C',
nl='\n';
cout << &stream << endl;
putc(c1, &stream);
putc(nl, &stream);
cout << "written to testfile" << endl;
fclose(&stream);
putc(c2, stdout);
putc(c3, stdout);
putc(nl, stdout);
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
FILE* testfile;
testfile = fopen("testfile.txt", "wt");
if (testfile != NULL )
{
cout << &testfile << endl;
cout << testfile << endl;
stream_writer(*testfile);
}
else
{
cout << "Unable to open file\n";
}
return a.exec();
}
An example of my console output after running the code:
0x7ffff6aed478
0x138a200
0x138a200
written to testfile
BC
void stream_writer(FILE & stream)
Here you are receiving a reference to a FILE object.
cout << &stream << endl;
Here you are printing the address of a FILE object, via a reference.
FILE* testfile;
Here you are declaring a pointer to FILE.
cout << &testfile << endl;
Here you are printing the value of the pointer.
stream_writer(*testfile);
Here you are passing the dereferenced pointer as an object reference to the called function.
It would be surprising if all of these had the same value.
Your expectations are misplaced.
cout << &testfile << endl; is printing the address of the FILE pointer itself: 0x7ffff6aed478
cout << testfile << endl; is printing the address that the pointer points to: 0x138a200
Memory at address 0x7ffff6aed478 is where the FILE pointer is stored, and it has the value of 0x138a200.
Memory at address 0x138a200 is where the actual FILE object is allocated, and the values here correspond to data in struct FILE{...}
stream_writer(*testfile); You're dereferencing to get the FILE object, passing it by reference to stream_writer(). cout << &stream << endl; You then are printing the address of the same FILE object again. Hence the third line of output is 0x138a200
I created a server/client connection. The server and client both are compiling correctly but when I run the client, it gives me a Segmentation Fault (core dumped)
I don't know what I am doing wrong with my memory allocations. The program is not dangling or anything. I think my program is writing to a read-only portion of the memory, or maybe accessing a memory that is not available.
If anyone can tell where is the bug I would really appreciate it.
client.cpp
#include <iostream>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdlib.h>
#include <unistd.h>
using namespace std;
int main() {
char a;
int client;
int portNum = 1500;
int bufsize = 1024;
char* buffer = new char (bufsize);
bool isExit = false;
char* ip;
strcpy(ip, "127.0.0.1");
struct sockaddr_in direc;
if ((client = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
cout << "Error creating socket..." << endl;
exit(0);
}
cout << "Enter # to end call" << endl;
cout << "\t\t\t[s] to begin with" << endl;
cin >> a;
cout << "Socket created successfully..." << endl;
direc.sin_family = AF_INET;
direc.sin_port = htons(portNum);
inet_pton(AF_INET, ip, &direc.sin_addr);
if (connect(client,(struct sockaddr *)&direc, sizeof(direc)) == 0)
cout << "Connection to the server " << inet_ntoa(direc.sin_addr) << endl;
cout << "Awaiting confirmation from the server..." << endl;
recv(client, buffer, bufsize, 0);
cout << "Response received: " << buffer;
cout << "\nRemember to put an asterisk at the end to send a message * \n Enter # to terminate the connection" << endl;
do {
cout << "Enter a message: ";
do {
cin >> buffer;
send(client, buffer, bufsize, 0);
if (*buffer == '#') {
send(client, buffer, bufsize, 0);
*buffer = '*';
isExit = true;
}
} while (*buffer != 42);
cout << "Mensage received: ";
do {
recv(client, buffer, bufsize, 0);
cout << buffer << " ";
if (*buffer == '#') {
*buffer = '*';
isExit = true;
}
} while (*buffer != 42);
cout << endl;
} while (!isExit);
cout << "Connection terminated. END PROGRAM\n\n";
close(client);
return 0;
}
I am assuming you don't need the server.cpp since it's all good and waiting for incoming connections.
Thanks!
There are a number of problems with this code, but the immediate and fatal errors are:
int bufsize = 1024;
char* buffer = new char (bufsize);
Allocates 1 character and tries to store the value of bufsize into it. bufsize is too big, so it gets truncated to 0. End result, buffer points to a single character, not an array of 1024, and that single value is set to 0. When you attempt to read bufsize bytes into buffer, you almost certainly overrun that single character and the behaviour is undefined. Most likely it either destroys some other program data (and possibly causes problems later) or writes into invalid memory and crash immediately.
I believe you meant
int bufsize = 1024;
char* buffer = new char[bufsize];
Instead,
char buffer[1024];
Will do what you want. Instead of bufsize, use sizeof(buffer). Further the following is often preferable:
Up at the top of the file, right under the includes:
#define BUFSIZE 1024
and then
char buffer[BUFSIZE];
Now you can use BUFSIZE or sizeof(buffer). Both are resolved during compilation so there is no performance cost.
2018 Addendum:
constexpr int BUFSIZE = 1024;
Will have the same effect in modern C++ (C++11 or newer) and does not have the the downsides of macro substitution from the #define.
The beauty of both options is the memory is self-managed. char* buffer = new char[bufsize]; requires a delete[] buffer somewhere in your code to put the memory back. And you have to make sure you get to that delete[] to prevent a leak. Don't use pointers and dynamic allocation unless you have to.
Next,
char* ip;
strcpy(ip, "127.0.0.1");
allocates a pointer, ip that is uninitialized. Most likely the address if contains is made up of whatever crap happened to be on the stack and does not point to a valid char array. Then "127.0.0.1" is written over whatever happened to be pointed to by ip. Similar effect to overrunning the end of buffer earlier.
Again, we know exactly what ip is going to point at, so the fix is easy:
char * ip = "127.0.0.1";
I prefer
char ip[] = "127.0.0.1";
but I have no reason for doing so.
2018 Addendum: I now have a reason for doing so. char * ip = "127.0.0.1"; is flat-out illegal in modern C++. String literals are constant arrays, and assigning them to non constant pointers can lead to much badness if the pointer is used to modify the string literal. In the old days we just ignored the problem and never wrote to the literal. Except when you did a few abstractions later and spent days or weeks debugging. Better to just cut the problem off at the source and copy the literal to a mutable array if there is a chance that it might be mutated. Even better is to remain const correct throughout the code if you can.
Next up,
recv(client, buffer, bufsize, 0);
Has two problems:
It discards the number of bytes read and the error codes returned. The program has no idea if it read anything at all due to a socket error or if it got the entire message, part of the message or more than the message.
It also demonstrates a misunderstanding of how TCP works. TCP does not work in nice, defined messages. Data written into the socket may be packed into the same out-bound packet with other messages. It may be split up across multiple packets that will arrive at different times. The logic behind this is out of scope for StackOverflow. Do some reading on TCP and streaming data.
But wait! There is more!
cin >> buffer;
Will overflow buffer even if fixed to the expected size if the user types in 1024 or more characters (do not forget the null terminator is required). Further, you don't know how many characters were input without counting them yourself. Painful and slow. Fortunately there is std::string.
std::string outbuf;
cin >> outbuf;
Solves both problems in one shot. It resizes itself and keeps a count of its contents. Neat, huh?
send(client, buffer, bufsize, 0);
Will send 1024 bytes of data even if the user typed in less. Or more. Yuck. Using outbuf from above,
send(client, outbuf.c_str(), outbuf.length(), 0);
Writes the correct number of characters every time, but if you want to preserve the string's terminating null, you'll have to send outbuf.length() + 1 characters.