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;
}
}
Related
My friends and I were playing with the C++ language. While doing so, we encountered something we couldn't understand.
Here is the code:
#include <vector>
#include <iostream>
void print(std::vector<char> const &input)
{
std::cout << input.size();
for (int i = 0; i < input.size(); i++)
{
std::cout << input.at(i) << " - ";
}
}
int main()
{
char cha = 'A';
char chb = 'B';
char * pcha = &cha;
char * pchb = &chb;
try
{
std::vector<char> a = {pcha, pchb};
//std::vector<char> a = {pchb, pcha};
print(a);
}
catch(std::exception e)
{
std::cout << e.what();
}
}
Output for this code:
A
When I comment out this first line try block and uncomment the second line, which comes to this:
try
{
// std::vector<char> a = {pcha, pchb};
std::vector<char> a = {pchb, pcha};
print(a);
}
Output becomes:
std:exception
I thought maybe the this occurs because of the different padding and alignments of the declared variables (char, char*), yet still didn't understand. You can find the code here to play around.
Thanks in advance.
std::vector<char> a = {pcha, pchb};
Here, you use the constructor of vector that accepts two iterators to a range. Unless the end iterator is reachable from the begin one, the behaviour of the program is undefined. Your two pointers are not iterators to the same range (i.e. elements of an array), so one is not reachable from the other. Therefore the behaviour of the program is undefined.
These would be correct:
std::vector<char> a = {cha, chb}; // uses initializer_list constructor
// or
char arr[] {cha, chb};
char * pcha = std::begin(arr);
char * pchb = std::end(arr);
std::vector<char> a = {pcha, pchb}; // uses the iterator constructor
#eerorika's answer explains your mistake.
However, I would like to dissuade you, and other readers, from using the second part of the his(?) corrected code snippet - not because it's incorrect, but because it's problematic coding practice:
I accept Nicolai Jossutis' suggestion of trying to uniformly initialize variables with curly brackets and no equals since (e.g.. mytype myvar {my_initializer};).
Freestanding pointers are dangerous beasts. Try to avoid them altogether, or minimize their existence to where you really need them. After all, you were "tempted" to use those pointers in an inappropriate way... so,
char arr[] {cha, chb};
std::vector<char> a = {std::begin(arr), std::end(arr)};
Don't create a dummy container just to create the one you really want. Just stick with the first line in #eerorika's suggestion (without the equals sign):
std::vector<char> a {cha, chb};
In fact, unless you really need it - you probably don't even want to create a variable-length container. So perhaps just
std::array<char, 2> a {cha, chb};
or with C++17's template argument deduction:
std::array a {cha, chb};
I am trying to print the following using the code as:
int main() {
char p[] = "hello";
char*t = p;
char**b = &t;
std::string s = b[0];
cout<<"string="<<s<<" b[0]="<<b[0];
}
The output I get is as expected:
string=hello b[0]=hello
Now the same thing I want to achieve using a function call in which I pass a variable by reference as:
void func(char**& p) {
char *k = (char*)malloc(8*sizeof(char));
k = (char*)"abc";
p = &k;
}
int main() {
char**j = NULL;
func(j);
std::string s1 = j[0];
cout<<s1;
}
Now I am getting a null string. What could be the reason and how to solve it ?
You have (at least) two problems:
The first is that you make p point to the local variable k.
The second is more subtle, and is that you reassign k losing the original memory you allocated and make k point to.
Then the usual spiel about never using arrays of char or pointers to char for strings, when you have std::string. And that you should never use malloc in C++, only new or new[]. And if you need new[] consider using std::vector instead (except for strings of course).
There is NO WAY to write code like this that follows any sort of standards of good programming. If you are serious about learning how to program you should abandon this mess and rewrite your code to do things the correct way. This is sort of mess is never necessary, even when interfacing with legacy code.
However the following 'works'
void func(char**& p) {
p = new char*;
*p = new char[8];
strcpy(*p, "abc");
}
And take note, I didn't need to use a cast.
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!
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.
I'm searching for an example or explanation why someone should (or should not) use triple-pointers in C/C++.
Are there any examples where triple-pointer arise?
I am especially looking for source-code which uses triple-pointers.
The best example that comes to mind is a sparse multi-level table. For instance one way to implement properties for Unicode characters might be:
prop_type ***proptable;
...
prop_type prop = proptable[c>>14][c>>7&0x7f][c&0x7f];
In this case proptable would need to have a triple-pointer type (and possibly quadruple pointer if the final resulting type is a pointer type). The reason for doing this as multiple levels rather than one flat table is that, at the first and second levels, multiple entries can point to the same subtable when the contents are all the same (e.g. huge CJK ranges).
Here's another example of a multi-level table that I implemented; I can't say I'm terribly proud of the design but given the constraints the code has to satisfy, it's one of the least-bad implementation choices:
http://git.musl-libc.org/cgit/musl/tree/src/aio/aio.c?id=56fbaa3bbe73f12af2bfbbcf2adb196e6f9fe264
If you need to return an array of pointers to variable length strings via a function parameter:
int array_of_strings(int *num_strings, char ***string_data)
{
int n = 32;
char **pointers = malloc(n * sizeof(*pointers));
if (pointers == 0)
return -1; // Failure
char line[256];
int i;
for (i = 0; i < n && fgets(line, sizeof(line), stdin) != 0; i++)
{
size_t len = strlen(line);
if (line[len-1] == '\n')
line[len-1] = '\0';
pointers[i] = strdup(line);
if (pointers[i] == 0)
{
// Release already allocated resources
for (int j = 0; j < i; j++)
free(pointers[j]);
free(pointers);
return -1; // Failure
}
}
*num_strings = i;
*string_data = pointers;
return 0; // Success
}
Compiled code.
If you use a linked list you have to store the address of the first element of the list ( first pointer ) .
If you need to change in that list you need another pointer ( two pointer)
If you need to pass your list that you are changing in two pointers and change it in another function you need another pointer ( three pointer )...
They are a lots of examples
I've used triple pointers in C++:
There is an interface written for a Java program:
https://github.com/BenLand100/SMART/blob/master/src/SMARTPlugin.h
and it takes an array of strings.
typedef void (*_SMARTPluginInit)(SMARTInfo *ptr, bool *replace, int *buttonc, char ***buttonv, int **buttonid, _SMARTButtonPressed *buttonproc);
Then in my program I do:
char* btnTexts[2] = {"Disable OpenGL_Enable OpenGL", "Enable Debug_Disable glDebug"}; //array of C-style strings.
void SMARTPluginInit(SMARTInfo* ptr, bool* ReplaceButtons, int* ButtonCount, char*** ButtonTexts, int** ButtonIDs, _SMARTButtonPressed* ButtonCallback)
{
*ButtonText = btnTexts; //return an array of strings.
}
but in C++, you can use a reference instead of pointer and it'd become:
void SMARTPluginInit(SMARTInfo* ptr, bool* ReplaceButtons, int* ButtonCount, char** &ButtonTexts, int** ButtonIDs, _SMARTButtonPressed* ButtonCallback)
{
ButtonText = btnTexts; //return an array of strings.
}
Notice now that "ButtonTexts" is a reference to an array of C-style strings now.
A char*** can be a pointer to an array of C-style strings and that's one time that you'd use it.
A very simple example is a pointer to an array of arrays of arrays.
Triple pointer is a pointer variable that points to a pointer which in turn points to another pointer. The use of this complex programming technique is that usually in which companies process tons and tons of data at one time .A single pointer would point to a single block of data (suppose in a large file) using the triple pointer would result in 3 times faster processing as different blocks of data(in the same file) can be pointed by different pointer and thus data could be accessed/processed faster (unlike 1 pointer going through the whole file).