Wrong code about c++ char*. Any body view? - c++

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
#define attr_size 3
int main(){
const char* attr[attr_size];
int i=0;
for(i=0;i<attr_size;i++){
char* t=(char*)malloc(sizeof(int));
sprintf(t,"%d",i);
string temp="attr";
temp+=t;
attr[i]=temp.c_str();
cout<<attr[i]<<endl;
free(t);
}
for(i=0;i<attr_size;i++){
cout<<attr[i]<<endl;
}
}
And the result is:
attr0
attr1
attr2
attr2
attr
attr2
Actually, I want to get the result that:
attr0
attr1
attr2
attr0
attr1
attr2
Maybe something wrong with loop. Anybody help me?

The problem is that the c_str return a pointer that is temporary. So when the loop continue it's iteration the object you got the pointer from is destructed and the pointer is no longer valid, leading to undefined behavior when you later dereference that pointer.
If you want an array of strings, why not declare it as an array of strings?
There are also other problems with your code, like you only allocating four bytes for a string that can be 12 (with sign and string terminator) characters.
I would suggest you remake your program like this:
#include <iostream>
#include <array>
#include <sstream>
const size_t ATTR_SIZE = 3;
int main()
{
std::array<std::string, ATTR_SIZE> attr;
for (int i = 0; i < ATTR_SIZE; ++i)
{
std::istringstream is;
is << "attr" << i;
attr[i] = is.str();
}
for (const std::string& s : attr)
std::cout << s << '\n';
}
The above uses some C++11 features like std::array (you can use std::vector instead) and range-base for loop (you can use normal iteration instead).

Related

Vector of an array of structs resets strings to be blank. C++

So I'm having a very confusing issue where I'm attempting to print a string from a vector of arrays of structs to the console. Integers print just fine however strings stored within these structs get set to "". I have no idea what's going on here but after setting up a test as shown bellow this issue is still persisting. Any help figuring this out would be greatly apricated.
Should also mention I'm still new to c++ so I apologise if the issue here is something simple.
#include <iostream>
#include <string>
#include <vector>
#include "Header.h"
//Test struct
struct testStruct
{
string testString;
int testInt;
};
testStruct testArray[1] = {
testArray[0] = {"String works", 69}
};
int main()
{
srand(time(NULL));
vector < testStruct > test;
test.push_back({ testArray[0] });
cout << test[0].testString << "\n"; // prints "", should print "String works"
cout << test[0].testInt << "\n"; // prints 69
characterCreation();
checkPlayerStats();
introduction();
return 0;
}
This surprised me. The following code is legal (syntactically at least)
testStruct testArray[1] = {
testArray[0] = {"String works", 69}
};
but if you replace it with the sensible version
testStruct testArray[1] = {
{"String works", 69}
};
then your program works as expected.
I expect your version has undefined behaviour because you are assigning (here testArray[0] = ...) to an array element that has not yet been created.
testStruct testArray[1] = {
This defines this array. This array, then, gets constructed. At what point, exactly, this array gets constructed is immaterial for the purposes of this question. It's sufficient to note that what goes inside { ... } gets evaluated and used to construct this array.
testArray[0] = {"String works", 69}
This expression constructs the first value of the array. This expression assigns a value to testArray[0].
The problem is that testArray[0] is not constructed yet, this is what's going on right now. This is undefined behavior. Just like what came first: the chicken or the egg. This is undefined.
You are seeing the results of undefined behavior, in the results of your program. The results of the program can be anything, and this just happens to be what shakes down, due to what your compiler and C++ library happen to produce, in terms of the executable code, before the dust settles.
So first of all you need to use std::vector, and std::cout as you havent used using namespace std.
But your main problem is:
testStruct testArray[1] = {
testArray[0] = {"String works", 69}
};
First of all it shouldnt be global as it does not need to be.
Second of all this is not correct:
testArray[0] = {"String works", 69}
You should not do this inside an array. What you probably meant to do is this:
testStruct testArray[1] = {{"String works", 69}}; // uses aggragate initialization.
So now this will have the correct output, with the following program:
#include <iostream>
#include <string>
#include <vector>
#include "Header.h"
//Test struct
struct testStruct
{
string testString;
int testInt;
};
int main()
{
testStruct testArray[1] = {{"String works", 69}};
srand(time(NULL));
vector < testStruct > test;
test.push_back({ testArray[0] });
cout << test[0].testString << "\n"; // prints "String works".
cout << test[0].testInt << "\n"; // prints 69.
characterCreation();
checkPlayerStats();
introduction();
return 0;
}
Assuming you have the Header.h header file

"expected expression" error when initializing an empty array [duplicate]

This question already has answers here:
A method to assign the same value to all elements in an array
(4 answers)
Closed 1 year ago.
I am trying to initialize an empty array that I initialized earlier in the program. However, whenever I compile my program I am given the error
expected an expression (C/C++(29))
Here is what my code looks like:
#include <iostream>
using namespace std;
int main(){
const int MAX_SIZE = 6;
int array[MAX_SIZE] = {12,-3,24,65,92,11};
for(int i=0;i<MAX_SIZE;i++){
cout << array[i] << " ";
}
array[MAX_SIZE] = {};
return 0;
}
The error is indicated right on the first curly brace of the empty array initialization. Also I am using Visual Studio Code on a Mac OS Big Sur.
This expression:
array[MAX_SIZE] = {};
Attempts to assign a value at index 6 to something that isn't an array. That's why it generates a compiler error. (And if it didn't, it would be assigning something to an invalid index in an array!)
You might be temped to think this...
array = {};
...would work, since it's similar for resetting members of objects to a default initialized state. But it doesn't work for arrays.
But this works:
std::fill(a, a+MAX_SIZE, 0); // #include <algorithm> if needed
And will assign every element in a to 0
Old school, "C" way for doing the same thing:
memset(a, '\0', MAX_SIZE*sizeof(int)); // #include <string.h> if needed
Or just manually
for (int i = 0; i < MAX_SIZE; i++) {
a[i] = 0;
}
Your trouble lies here: array[MAX_SIZE] = {};
The initialization syntax only work when you are initializing an array.
Though it does actually compile for me with GCC, the resulting program then crashes.
If you want to fill the array with a value. Either zero or something else, you may want to use std::fill.
Plain C-style arrays are not assignable, the type array[size] = {...}; syntax is only for declaration and initialisation.
You can use std::array<T,N> instead, like this:
#include <array>
#include <iostream>
using namespace std;
int main(){
const int MAX_SIZE = 6;
std::array<int, MAX_SIZE> arr = {12,-3,24,65,92,11};
for(int i=0;i<MAX_SIZE;i++){
cout << arr[i] << " ";
}
// reset all elements back to 0
arr.fill(0);
return 0;
}

How to fix "no instance of overloaded function" in vector push_back?

I want to write a function which takes as input a pointer to a vector pointer which point to a string (Dictionary) and a pointer which points to a char (p). The function will check if the char is in the Dictionary and if it isn't there it adds the p in the vector Dictionary.
My code:
#include <iostream>
#include <string>
#include <vector>
using std::string;
using std::vector;
std::vector<string *> dictionary;
void manageDictionary(vector<string *> * dictionary, char *p) {
for (unsigned int i = 0; i < (*dictionary).size(); i++) {
string * pstring = (*dictionary).at(i);
if ((*pstring).compare(p)) {
(*dictionary).push_back(p);
}
}
}
However, the visual studio compiler shows I have an error in the if statement just before the push_back method (.). When I hover on the error, it says "no instance of overloaded function".
I added the std::vector<string *> dictionary; at the beginning, still cannot figure out where the problem is.
dictionnary is a vector of std::string*. std::string* and char* are totally unrelated types. To convert from char* to std::string* will require you to create a new string that contains the value of p for your dictionnary, rather than passing a char* directly. This change will allow your example to compile, but the resulting function is error prone.
#include <string>
#include <vector>
using std::string;
using std::vector;
void manageDictionnary(vector<string *> * dictionnary, char *p) {
for (unsigned int i = 0; i < (*dictionnary).size(); i++) {
string * pstring = (*dictionnary).at(i);
if ((*pstring).compare(p)) {
(*dictionnary).push_back(new string(p));
// Make a new string ^^^^^^^^^^
}
}
}
This solution will require you to delete your strings manually which is not the way things are done in c++. Changing from std::vector<std::string*> to simply std::vector<std::string> will solve this problem, and avoid you headaches in the future. There are other unnecessary pointers that can be removed. Since at(i) returns a string& then we should change pstring to string&. Since dictionnary is not optional (can't be nullptr) and always points to the same vector we can also change it to a vector<string>&.
void manageDictionnary(vector<string> & dictionnary, char *p) {
for (unsigned int i = 0; i < dictionnary.size(); i++) {
string & pstring = dictionnary.at(i);
if (pstring.compare(p)) {
dictionnary.push_back(p);
}
}
}
This latest version will work fine and is much more in line with c++'s philosophy for resource management. I recommend you read on a few topics :
Standard algorithms like std::find.
Range-based for loops.
const-correctness.
pointer vs reference.
Additionally, consider using std::set<string> or std::unordered_set<string> for a more convenient representation of a dictionnary.
In the future, note that the preferred way to access a pointer's methods is ptr->foo() rather than (*ptr).foo().

String declaration initial length when not initialised

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int main(){
char a[20];
cout<<strlen(a)<<endl;
return 0;
}
The output of this code is 11.
Why 11? When I have not initialised it.
As stated here: http://en.cppreference.com/w/cpp/string/byte/strlen,
The behavior (of strlen(str)) is undefined if there is no null character in the character array pointed to by str.
The issue you are facing is caused by uninitialized memory. With char a[20]; you are only reserving memory space, but you are not initializing it. Those 20 bytes can have any possible value and you have no guarantees that any of them is set to 0. That causes the unespected return value of the strlen() call, you simply were lucky that the function found a byte set to 0 before it could cause a crash.
To avoid any problem you should initialize your variables before using. For a null terminated sequence of char you can initialize like so:
char a[20] = "";
Or you can use std::string instead:
#include <iostream>
#include <string>
int main() {
std::string a;
std::cout << a.length() << std::endl;
return 0;
}
The output, if you are wondering, is 0.
If you find uninitialized array's length,The behavior is undefined. if you want correct result initialize it. or use this:
int a[20] = {};
or
memset(a,'\0',20) and then after check the length.

int to string, char* itoa

trying to get ‘sval’ to contain the string “$1” – “$500” for array indexes 0-499. in the following code, however itoa is giving me strange strings in the code below:
#include<iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
typedef struct data_t {
int ival;
char *sval;
} data_t;
void f1(data_t **d);
int main()
{
data_t *d;
d=static_cast<data_t*>(malloc(500)); //is this even needed?
d = new data_t[500];
f1(&d);
}
/* code for function f1 to fill in array begins */
void f1(data_t **d)
{
int i;
char str[5];
for (int i=0; i<500; i++)
{
(*d)[i].ival=i+1;
itoa (i,str,10);
(*d)[i].sval= str;
}
}
it also seems itoa has been depreciated, but that was what i got when i googled int to string
You don't need ltoa, cout should be just fine. Why do you need to keep the number and its string representation in the array? when you do cout << 10 you get "10" on the output, you don't need any conversions of your own
You, on the other hand, do ltoa without allocating any memory for the strings, which is not healthy as you have probably noticed. You use a local variable (the same, for all the 500 array members), which you try to access after you exit the function - a big no-no, its undefined behavior.
And:
d=static_cast<data_t*>(malloc(500)); //is this even needed?
d = new data_t[500];
No. Not only not needed - shouldn't be there at all! When in C++ - use new and delete, never malloc, that's a C function.