What I'm trying to do here is quite simple. But some way, some how I'm missing something. I'm trying to "pre-declare" an array with strictly string elements in such a way that I can update the array contents during a specific period (periodically). So here are the snippets:
string ShotBox[] = {}; //"Pre-Declare" array that could contain as many elements here
Then I have a loop within my Update container. Snippet's:
for (int i = 0; i < sizeof(ShotBox) - 1; i++){
std::string soa = sPath;
std::string so = soa + ShotBox[i];
char *cstr = new char[so.length() + 1];
strcpy(cstr, so.c_str());
scPath = cstr;
}
All is fine with everything except the fact that whichever way I try to "pre-declare", I get a memory access violation. In this very exact snippets, the exact error is: an empty array is invalid for an array with unspecified bound.
I tried using "vector" but can't seem to work around it. What's the way to solve this? Please I don't want libraries. I need direct short methods or something of such.
Use std::vector<std::string>.
The vector manages an internal array.
std::vector<std::string> ShotBox; // (empty)
ShotBox.push_back(a_string); // add a string to the internal array
std::cout << ShotBox[0] << '\n'; // print first element
The problem of memory access violation itself is caused by your misunderstanding of sizeof operator. Specifically, sizeof(ShotBox) is the size (in bytes) of your array, not the ShotBox[] array size.
for (int i = 0; i < sizeof(ShotBox)/sizeof(std::string); i++) {
...
}
Inside the for loop ShotBox[] elements aren't updated at all. The only thing that happens is concatenation of sPath with ShotBox[i] into a new C string 'cstr'. If your aim is to update ShotBox[i] element, just add the following assignment to the end of for loop:
for (int i = 0; i < N_SHOT_BOX; i++) {
...
ShotBox[i] = so;
}
It's much more convenient to use std::vector for working with collections of variable size:
#include <string>
#include <vector>
#include <memory.h>
int main() {
std::vector<std::string> ShotBox{"str1", "str2", "str3"};
for (int i = 0; i < ShotBox.size(); i++){
std::string soa = sPath;
std::string so = soa + ShotBox[i];
char *cstr = new char[so.length() + 1];
strcpy(cstr, so.c_str());
ShotBox[i] = cstr;
}
return 0;
}
Galik's answer suggesting std::vector is the Modern C++ way to do what you want to do.
The reason your code doesn't work is that the following line of code doesn't do what you think it does
string ShotBox[] = {}; //"Pre-Declare" array that could contain as many elements here
Try adding the following to your program ...
std::cout << sizeof(ShotBox) << std::endl;
... and you should find that you've declared an array that is zero bytes long. Indeed some compilers will treat an empty initializer as an error if the array bounds are not specified.
In the C++ language arrays are fixed length entities. One way to approximate a dynamic array is to use a pointer and to use memory management functions to allocate a larger array and then copy the old array contents into the new larger array.
But that is a really bad idea.
Doing it correctly with exception safety and efficiency is hard to do and if you do manage it, you'll have re-implemented std::vector which seems like wasted effort!
Related
I have an array of bytes that I want to change how it's accessed. Here's the array:
char bytes[100];
I want to have another array that changes how the original array is accessed. If we could put references in array, it would look something like this:
char& bytes_ref[50];
for(size_t i = 0; i < 50; i++){
bytes_ref[i] = bytes[i * 2];
}
Though array of references aren't valid. I came up with this that in theory does what I want:
#include <iostream>
struct Byte {
char* ref;
Byte(){}
Byte(char& c){
ref = &c;
}
operator char&() const {
return *ref;
}
};
int main(){
char bytes[100];
Byte bytes_ref[50];
for(size_t i = 0; i < 50; i++){
bytes_ref[i] = bytes[i * 2];
}
}
Though this works like I want it to, it takes up a ton of space.
Is there some way to do this without using up 7 more bytes per entry? My instinct is no, but I'm hopeful there may be some kind of special functionality in C++ that could do this, or maybe do some direct memory manipulation and access.
The reason I want to do this is I have an array of bytes that represent an image in NV21 format. I want to create a separate array that references the bytes in the original buffer but takes half the pixels, effectively resizing the image on the fly.
I have to pass a char** to an uncontrolled library.
Thanks in advance!
I do not think you can use less memory than one pointer per element
If you need to pass an array of char* to an uncontrolled library, I understand that you have to allocate the whole array because that is what the library is expecting. The code would like:
std::array<char*, 50> bytes_ref;
for(size_t i = 0; i < bytes_ref.size(); ++i){
bytes_ref[i] = &bytes[i * 2];
}
Then, you can pass the array as:
f(bytes_ref.data());
If you would not need to use char**, you would have more options. You may use std::reference_wrapper although its size is similar to a pointer. If you always have to skip 2 elements, you may create an object for this. For example:
class Wrapper {
public:
Wrapper(char *origin) : m_origin(origin) {}
char* operator[](size_t index) {return m_origin + 2*index;}
private:
char *m_origin;
};
The above will return a pointer to every 2 elements using the [] operator.
EDIT: Im quite new to c++ and programming as a whole.
I'm supposed to make a program where i use stucts and and an array of structs.
Security council < > Member of Security council
My task was to use the concept of "UML aggregation" to create a program where I use structs and struct arrays. (I hope you understand what I'm trying to say)
Since a Member of a Security council is a part of a Security council, and not the other way around, the struct of Security council must have an array of its members.(bear with me)
//example
struct Member_sc{
char * name;
int age;
};
struct Security_council{
Member_sc members[10];
};
Now, I've created this program and everything works perfectly (according to my teacher), but now she told me create an exact copy, but instead of the "members" array I must use an array of pointers to the Member_sc structs. Since I havent completely figured out how pointers work, I have come across some problems.
I can post the code to the original program if needed, but it contains 4 files(main, header, and some function files) and it would be a pain to try and post it here.
here is the prototype (all in one file, for now)
#include <iostream>
using namespace std;
struct member_sc{
string name;
};
struct security_council{
member_sc *point;
security_council **search; // ignore this for now
int n;
security_council():n(0){}
};
void in_mem( member_sc &x){
getline(cin,x.name);
}
void out_mem(member_sc &x){
cout<<x.name<<endl;
}
void in_SC(security_council &q, member_sc &x){
int num; //number of members
cin>>num;
for(int i=0; i<num; ++i){
in_mem(x);
q.point[q.n]=x;
q.n++;
}
}
void out_SC(security_council &q,member_sc &x){
for(int i=0; i<q.n; ++i){
out_mem(q.point[i]);
}
}
int main(){
member_sc y;
security_council x;
in_mem(y); // works
out_mem(y); // works
in_SC(x,y); // crashes after i input the number of members i want
out_SC(x,y); //
system("pause");
return 0;
}
The program crashes after you input the number of members you want in your Security council.
Is my way of thinking right? or should I use dynamic memory allocation?
in addition to that (my teacher gave me an additional task) create a search function using pointers. i thought that pointer to pointer may be good for that, but im not sure.
Any help or advice would be greatly appreciated.
( i think ill figure out the search thingy once i figure out how pointers to structs work)
The first part of your issue is this:
cin >> num;
this reads only the digits that have been typed and stops at the newline. Then, in in_mem the call to getline immediately reads a newline. You need to do:
cin >> num;
cin.ignore();
this will drain the input stream of any remaining input, or catch up so to speak.
However your core problem is that you don't allocate any memory for "point" to point to.
A pointer is just a variable holding a value that happens to be the address (offset from 0) of a thing in memory. If you are going to the airport and write "Gate 23" on a post-it note, the post it note is a pointer and "Gate 23" is the value.
In your code, that variable is uninitialized and will either be 0, if you are lucky, or some random address in memory if you aren't so lucky.
To the airport analogy: you arrive at the airport and find that your post-it note has "pizza" written on it. Not helpful.
Your teacher has actually specified an "array of pointers". Break that down: pointer to what? member_sc, that's member_sc*. And now make it an array
member_sc* pointers[10];
NOTE: This is not good, modern C++ - in modern C++ you would use something called a smart pointer (std::unique_ptr) probably.
std::unique_ptr<member_sc[]> pointers(new member_sc[10]);
Now you have 10 pointers instead of just one, and all of them will need some allocation to point to. The easiest way to do this is with the new keyword and the copy constructor:
for (int i = 0; i < num; i++) {
in_mem(x);
pointers[q.n] = new member_sc(x); // make a clone of x
q.n++;
}
or in modern C++
for (int i = 0; i < num; i++) {
in_mem(x); // x is temporary for reading in
pointers[q.n] = std::make_unique<member_sc>(x);
q.n++;
}
However there is a limitation with this approach: you can only have upto 10 security council members. How do you work around this? Well, the modern C++ answer would be to use a std::vector
std::vector<member_sc> members;
// ditch n - vector tracks it for you.
// ...
for (int i = 0; i < num; ++i) {
in_mem(x);
q.members.push_back(x);
// q.n is replaced with q.members.size()
// which is tracked automatically for you
}
but I'm guessing your teacher wants you to actually understand pointers before you get to forget about them with modern luxuries.
We need to re-use the pointer stuff we've just used above and change "pointers" to an array of pointers.
Which means we're going to want a pointer to a set of pointer-to-member_sc.
member_sc** pointers;
We'll need to assign some memory for this to point to:
cin >> num;
cin.ignore();
if (num == 0) {
// do something
return;
}
pointers = new member_sc[num];
luckily, using a pointer to an array is as easy as using an array, the only major difference being that you lose the size-of-array information -- all you have is the address, not the dimensions.
for (int i = 0; i < num; i++) {
in_mem(x);
q.pointers[i] = new member_sc(x);
q.n++;
}
I'm deliberately not providing you with a complete working example because this is obviously for a class.
You never initialize the memory that the point member refers to, yet then in statement q.point[q.n]=x; you attempt to use it.
Basically, after you read in the number of members, and before the for loop where you read in the individual members, you need to allocate an array of an appropriate number of member_sc objects and store it in q.point. Don't forget to free this memory when done using it.
Once you do that, you can also remove the member_sc &x argument from both in_SC and out_SC, as that will become unnecessary.
Finally, some validation of your input seems to be in place. Consider what will happen if the user enters a negative number, and you attempt to use that directly to determine the size of memory to allocate.
Here's a simple example showing how to use a dynamically allocated array of structures:
#include <iostream>
#include <string>
struct member_sc {
std::string name;
};
void test_array(int count)
{
if (count <= 0) {
return; // Error
}
// Allocate an array of appropriate size
member_sc* members = new member_sc[count];
if (members == nullptr) {
return; // Error
}
// ... fill in the individual array elements
for(int i(0); i < count; ++i) {
// ... read from input stream
// I'll just generate some names to keep it simple
members[i].name = "User A";
members[i].name[5] += i; // Change the last character, so we have different names
}
// Now let's try printing out the members...
for(int i(0); i < count; ++i) {
std::cout << i << ": " << members[i].name << "\n";
}
delete[] members;
}
int main(int argc, char** argv)
{
for(int count(1); count <= 10; ++count) {
std::cout << "Test count=" << count << "\n";
test_array(count);
std::cout << "\n";
}
return 0;
}
Example on Coliru
Of course, there are many other issues with this style of code, but I believe that's beside the point of this question. For example:
Instead of using bare pointers, it would be more appropriate to use some kind of a smart pointer.
Instead of a simple array, use some kind of collection, such as a vector.
Since you are asked to use an array of pointers, do so: replace
Member_sc members[10];
with
Member_sc* members[10];
Then fill out that array using dynamic memory allocation. As a matter of good form, at the end of the program remember to release the dynamic memory you have used.
I am trying to read from a file and put each new line/entry in to an array. However, I am more primarily familiar with C# and C++ isn't my thing. The reason I need to do this is for a project and I am the only one that is willing to do this part.
I do not know how to properly convert character types or if it is possible. I have tried searching around the internet but have not found any answers regarding something like my issue here. Also, because I do not know what causes an illegal sizeof operand I do not know what is wrong here.
#include "..\STDInclude.h"
// TODO: Fill that list with names
char* Bots::NameList[] = {};
void Bots::GetNames()
{
using namespace std;
ifstream file("bot_names.txt");
if (file.is_open())
{
for (int i = 0; i < 48; i++)
{
file >> Bots::NameList[i];
}
}
}
void Bots::Initialize()
{
// Replace staff array with custom one
*(char***)Addresses::BotArray1 = Bots::NameList;
*(char***)Addresses::BotArray2 = Bots::NameList;
*(char***)Addresses::BotArray3 = Bots::NameList;
// Apply new array size
int size = (sizeof(Bots::NameList) / sizeof(Bots::NameList[0]));
*(BYTE*)Addresses::BotArraySize1 = size;
*(BYTE*)Addresses::BotArraySize2 = size;
*(BYTE*)Addresses::BotArraySize3 = size;
*(BYTE*)Addresses::BotArraySize4 = size;
}
Arrays in C++ are of fixed size. So when you write char* Bots::NameList[] = {} , you have an empty array of c-strings (aka char*).
Worse, when you later write file >> Bots::NameList[i]; you are writing null terminated c-strings to uninitialized pointers, which will cause memory corruption.
Unless fundamental rewrite, this code is doomed to fail. I strongly suggest that you replace use of char* with std::string and that you switch from fixed size arrays to vectors.
std::vector<std::string> Bots::NameList;
void Bots::GetNames()
{
...
for (int i = 0; i < 48; i++)
{
string s; // space separated strings ? sure ?
file >> s; // or getline(file, s) if you want lines
NameList.push_back(s);
}
}
}
Aditional remark:
I can't tell for sure, as I don't know the definition of Addresses members, but statements like the following are relatively suspicious:
*(char***)Addresses::BotArray1 = Bots::NameList;
It suggests that Addresses::BotArray1 is an array or a pointer. But the fact that you are casting with (char***) suggest that you tried to fix a type mismatch. And dereferencing the casted pointer will make sense only if BotArray points already to a valid char** pointer in which the address of NameList should be stored.
In C++ an array must be sized when created and then it is fixed, so char* Bots::NameList[] = {}; is a zero element array and is stuck that way. Worse, in file >> Bots::NameList[i] nothing ever allocated storage for Bots::NameList[i], so your program is writing into uninitialized memory. Probably a BOOM waiting to happen. I'm going to suggest something completely different.
in the Bots class definition:
std::vector<std::string> NameList;
Then later...
void Bots::GetNames()
{
std::ifstream file("bot_names.txt");
if (file.is_open())
{
for (int i = 0; i < 48; i++)
{
std::string temp;
file >> temp;
NameList.push_back(temp);
}
}
}
Addresses::BotArray1..N must also become std::vectors and Addresses::BotArraySize1..N are made redundant because vectors know their size.
Ok, I have no idea what to do here:
struct
{
char nombre[30];
int codigo;
}productos[10];
int z = 0;
char tempchar[30];
for (z=0; z<9; z++) {
if (productos[z].codigo>productos[z+1].codigo) {
tempchar = productos[z].nombre;
productos[z].nombre = productos[z+1].nombre;
productos[z+1].nombre = tempchar;
}
}
I get the following error message:
ISO C++ forbids assignment of arrays
There's obviously more code but I just included what it has to do with the error.
I just want to sort the names of the product by code. So, what can I do here?
Is it in C or in C++?
In C you should use strcmp(3) to compare strings and strcpy(3) to copy them. Be very careful of buffer overflow (perhaps use strncmp and strncpy etc...). Ensure that all your strings are null-terminated. Use qsort(3) for sorting.
In C++, you should use std::string which knows about <; you can then use std::sort to sort them. And if you use ordered containers like std::set or std::map they will be ordered by construction.
Use strcpy to assign char arrays
strcpy(tempchar, productos[z].nombre);
strcpy(productos[z].nombre, productos[z+1].nombre);
strcpy(productos[z+1].nombre, tempchar);
When sorting an array of structs, you typically want to swap the whole struct, not just a single member. Luckily for you, the assignement operator works on structs, even if they contain arrays. So your sort algorithmus will be less buggy if you do this:
temp = productos[z];
productos[z] = productos[z+1];
productos[z+1] = temp;
(how to declare temp is left as exercise for the reader)
Alternatively, if you are allowed to use c++, you can do
std::swap(productos[z],productos[z+1]);
Just remember, your sort algorithmus is still buggy. You should lookup "bubblesort" for a dead easy sort algorithmus you can implement. Or even better, if this is not an exercise, use an existing implementation like qsort or std::sort
there is another way
struct
{
char *nombre = (char*)malloc(sizeof(char) * 30);
int codigo;
}productos[10];
int z = 0;
char *tempchar = (char*)malloc(sizeof(char) * 30);
for (z=0; z<9; z++) {
if (productos[z].codigo>productos[z+1].codigo) {
tempchar = productos[z].nombre;
productos[z].nombre = productos[z+1].nombre;
productos[z+1].nombre = tempchar;
}
}
In a program I allocate a huge multidimensional array, do some number-crunching, then only the first part of that array is of further interest and I'd like to free just a part of the array and continue to work with the data in the first part. I tried using realloc, but I am not sure whether this is the correct way, given I must preserve the data in the array and preferably avoid copying of that chunk in memory.
#include <cstring>
#include <cassert>
#include <iostream>
using namespace std;
void FillArrayThenTruncate(char* my_array, const int old_size, int* new_size);
int main() {
const int initial_size = 1024*1024*1024;
char* my_array = static_cast<char*>(malloc(initial_size));
assert(my_array);
int new_size;
FillArrayThenTruncate(my_array, initial_size, &new_size);
for(int i = 0; i < new_size; ++i) cout << static_cast<int>(my_array[i]) << endl;
}
void FillArrayThenTruncate(char* my_array, const int old_size, int* new_size) {
//do something with my_array:
memset(my_array, 0, old_size);
for(int i = 0; i < 10; ++i) my_array[i] = i % 3;
//cut the initial array
*new_size = 10;
void* new_array = realloc(my_array, *new_size);
cout << "Old array pointer: " << static_cast<void*>(my_array) << endl;
cout << "New array pointer: " << new_array << endl;
my_array = static_cast<char*>(new_array);
assert(my_array != NULL);
}
UPDATE:
* Please do not bother to suggest to use STL. The question is about C array.
* Thanks to "R Samuel Klatchko" for pointing out the bug in the code above.
I assume you're using this for learning... otherwise I'd recommend you look into std::vector and the other STL containers.
The answer to the title question is No. You have to either compact the existing elements, or you need to allocate new space and copy the data you want. realloc will either extend/contract from the end or allocate new space and copy the existing data.
If you're working with such a large data set, you might as well just have a collection of chunks rather than a monolithic set. Maybe avoid loading the whole thing into ram to begin with if you only need certain parts.
For C++, use STL containers instead of handling your memory manually. For C, there is realloc().
Yes, if you allocate with malloc, you can resize with realloc.
That said, realloc is allowed to move your memory so you should be prepared for that:
// Only valid when shrinking memory
my_array = realloc(my_array, *new_size);
Note that if you are growing memory, the above snippet is dangerous as realloc can fail and return NULL in which case you will have lost your original pointer to my_array. But for shrinking memory it should always work.