Here is a problem. When I try to convert it by using strncpy_s, array has some type of "trash data" from memory in the end of it. Even when I fill buffer with "\0". How to convert it clear?
typedef class Ryadok {
private:
int LengthOf = 0;
char text[20];
string* address;
public:
Ryadok(string strin) {
this->text[0] = '\0';
memset(text, '\0', sizeof(text));
strncpy_s(text, strin.c_str(), sizeof(text) - 1);
this->address = &strin;
for (int i = 0; i < sizeof(strin); i++) {
cout << this->text[i];
}
}
~Ryadok() {
}
}*cPtr;
int main()
{
Ryadok example("sdsdfsdf");
}
The idea to use c_str() function to convert the std::string to a a-string. Then we can simply call strcpy() function to copu the c-string into char array
std::string s = "Hello World!";
char cstr[s.size() + 1];
strcpy(cstr, s.c_str()); // or pass &s[0]
std::cout << cstr << '\n';
return 0;
When using the strncpy_s function you tell it to copy as many chars as will fit into your buffer "text". Since the string you create the "example" instance with is shorter, the copy function will keep going after the end of the actual string.
That is where your garbage comes from. Even worse you risk a Segmentation Fault this way. Your code might access parts of the RAM it is not allowed to read from. That will cause it to crash.
You are right though to copy the data pointed to by the return of c_str(). The pointer returned by c_str() points to data that belongs to the std::string object and might be changed or even invalidated by that object. (Read more here)
Here's a modified version of your code that should avoid the garbage:
typedef class Ryadok {
private:
int LengthOf = 0;
char text[20];
string* address;
public:
Ryadok(string strin) {
this->text[0] = '\0';
memset(text, '\0', sizeof(text));
if(strin.length()+1 <= sizeof(text)) {
strncpy_s(text, strin.c_str(), strin.length()+1);
} else {
//some error handling needed since our buffer is too small
}
this->address = &strin;
for (int i = 0; i < sizeof(strin); i++) {
cout << this->text[i];
}
}
~Ryadok() {
}
}*cPtr;
int main()
{
Ryadok example("sdsdfsdf");
}
Related
I have been given a task, where I need to create the string_copy function Note that the function body and prototypes have been given by the source and that needs to be maintained. The portions written by me are after the comment write your code here.
#include <iostream>
using namespace std;
int string_length(const char* string_c);
char* string_copy(const char* string_c);
int main()
{
const char* string_c = "This is a string and is a long one so that we can create memory leaks when it is copied and not deleted";
// write your code here
int length = string_length(string_c);
cout << "Copied String: " << string_copy(string_c) << endl;
return 0;
}
int string_length(const char* string) {
int length = 0;
for (const char* ptr = string; *ptr != '\0'; ++ptr) {
++length;
}
return length;
}
char* string_copy(const char* string) {
// we need to add 1 because of ’\0’
char* result = new char[string_length(string) + 1];
// write your code here (remember zero-termination !)
int i;
for (i = 0; string[i] != '\0'; ++i)
{
result[i] = string[i];
}
result[i] = '\0';
return result;
}
Now task tells me
that it is very important that any memory allocated with e=new TYPE is
released later with delete e (and a=new TYPE[size] with delete [] a)
else this will lead to an error.
It is not exactly clear if error means compile/runtime error or error as in my task did not meet the requirement error.
My question is, in this code how do I delete the intermediate dynamically created result array? If I delete result, won't it fail the purpose of the task? Then how am I to respect the quotation above or maybe simulate memory leak as given in the long string constant?
Thanks.
EDIT: Why the negative votes? Please at least explain the reason! I am not asking any solution or something, but mere suggestion if I am missing some point or not!
The caller of string_copy would be responsible for releasing the memory when it's done with it by calling delete[] on it.
This is, by the way, a terrible way to write C++ code. You should be using std::string or std::vector<char> or something like that.
Here's why:
int length = string_length(string_c);
char* copy = string_copy(string_c);
cout << "Copied String: " << copy << endl;
delete[] copy;
return 0;
Yuck.
In fact the ideal solution is to use std::string and not char *. There is no real need of using char * instead of std::string in your example.
With std::string:
You don't need to new anything
You don't need to delete anything
You can do everything with std::string, that you do with char *.
This problem is blowing my mind right now.
int main()
{
char inputChar;
char *buffer = nullptr;
int size = 0;
read(buffer); //this is the line causing problems...
int numberOfFrames = (size / MAX_FRAME_SIZE) + 1;
frame array[numberOfFrames];
for(int i = 0; i < size; i++)
{
buffer[i] = appendParityBit(buffer[i]);
}
constructFrame(buffer, size, array);
transmitFrames(array, numberOfFrames);
}
int read(char *buffer)
{
int fileSize;
ifstream myfile ("inputFile");
if (myfile.is_open())
{
fileSize = getFileLength(myfile);
buffer = new char[fileSize];
myfile.read(buffer, fileSize);
myfile.close();
}
return fileSize;
}
int getFileLength(ifstream &myfile)
{
myfile.seekg(0, ios::end);
int size = (int) myfile.tellg() - 1;
myfile.seekg(0, ios::beg);
return size;
}
now if i do a
cout << read(buffer);
on the line that is causing problems, i receive an integer back...great, perfect. but if i try to do
size = read(buffer);
my program crashes...i'm at a loss.
You are passing a variable by value (doesn't matter if it is a pointer or not). On the receiving end, the function makes a local copy of what is passed, works with the local copy, and poof, the local copy goes away when the function returns.
This occurs regardless of whether what you're passing is a pointer or not. For example, take this simple code:
void foo(int x)
{
x = 10;
}
int main()
{
int val = 0;
foo(val);
cout << val; // how come val is still 0 and not 10?
}
Note that val is still 0, even though the function is changing the parameter that is being passed. To fix this problem, you pass a reference to the value that will be changed:
void foo(int& x)
{
x = 10;
}
int main()
{
int val = 0;
foo(val);
cout << val; // now val is 10
}
With pointers, the rules don't change. You need to pass a reference to the pointer to have the change reflect back to the caller:
int read(char*& buffer)
{
int fileSize;
ifstream myfile ("inputFile");
if (myfile.is_open())
{
fileSize = getFileLength(myfile);
buffer = new char[fileSize];
myfile.read(buffer, fileSize);
myfile.close();
}
return fileSize;
}
Now the buffer in that function is not a local copy, but a reference to the variable you passed.
The other method (which is more "C" style) is to pass a pointer to the thing you want to change. You want to change the pointer value, so you pass a pointer to the pointer:
int read(char** buffer)
{
int fileSize;
ifstream myfile ("inputFile");
if (myfile.is_open())
{
fileSize = getFileLength(myfile);
*buffer = new char[fileSize];
myfile.read(buffer, fileSize);
myfile.close();
}
return fileSize;
}
// the caller
char *buffer;
//...
read(&buffer);
Of course, we have to change the syntax since it is a pointer that is being passed, thus we need to dereference it.
You are passing your buffer (char*) by value. Even when you allocate the buffer in your read() routine, this modifies local copy of the pointer. When you return from read(), you still have the old unititialized value of the pointer, which is not usable. To alleviate the issue, you can pass your buffer by reference.
I think the other answers have identified your coding error.
I note that you have tagged this as C++ ... and I suggest that perhaps your error would not have occurred if you used C++ features.
I have found the following (in SO and else where). It is similar, but relies on the strongly tested std::string memory management, and the file size requires no extra code on your part.
size_t read(std::string& buffer)
{
std::ifstream sIn("inputFile");
if (!sIn.is_open())
{
std::stringstream ssErr;
ssErr << "Can not open file '" << "inputFile" << "'" << std::endl;
throw ssErr.str();
}
std::stringstream ss(buffer);
ss << sIn.rdbuf(); // one line transfer of file contents
sIn.close(); // close sIn when we are done with it
if(sIn.bad())
throw "Err: sIn.rdbuf()";
return (ss.str().size());
}
Somewhere you might want a std::char array ... note that the c-style result (null terminated string) is available in buffer.c_str().
You can load any size text file (that fits in your memory) using this technique.
I need to pass a char pointer to function, then change the value that it points to inside the function and print values outside the function.
The problem I have is that I'm losing it when I leave function and try to print it outside. What can I do to avoid this?
This is an code example:
char array[] = "Bada boom";
char *pText = array;
reverseText(pText);
cout << (pText);
cout should print
moob adaB
When I print inside the function, everything is fine(it prints reversed).
My task is to print It out outside the function (as you can see in a 4th line of code)
This is the full of code which have the bug (printing inside func works, outside didn't work)
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
char reverseText(char *text);
int main(){
char array[] = "Bada boom";
char *pTekst = array;
reverseText(pTekst);
cout << (pTekst); //in here it doesn't work
}
char reverseText(char *text){
char befRev[100]; int lenght=-1;
/*until *text doesn't meet '\0' */
for(int i=0;*text!='\0';i++){
befRev[i]=(*text);
text++;
lenght++;
}
/*reversing*/
int j=0;
for(int i=lenght;i>=0;i--){
*(text+j)=befRev[i];
j++;
}
for(int i=0;i<=lenght;i++) //in here it does print the right value
cout << text[i];
};
Just re-arrange the array in-place. The pointer itself doesn't need to change:
#include <cstring>
#include <algorithm>
void reverseText(char* array)
{
auto len = std::strlen(array);
std::reverse(array, array+len);
}
int main()
{
char array[] = "Bada boom";
char *pText = array;
reverseText(pText);
std::cout << pText << std::endl;
}
Output:
moob adaB
If you really wanted to provide a pointer that points to a different address to the caller, you could simply return it:
char* foo(char* stuff)
{
char* tmp = ....;
...
// do some stuff
...
return tmp;
}
Alternatively, you could pass the pointer by reference, but the intent is less clear than in the previous version:
void foo(char*& stuff)
{
stuff = something_else;
}
But in both cases, you must make absolutely sure the thing the new pointer points to is valid outside of the function. This might require some dynamic memory allocation. For your case, it seems the best and simplest option is to re-arrange the array in place.
To answer your question, you have an error in logic. Notice that in your first loop in reverseText you increment the local pointer text. In your second loop you did not reset text to it's original value so beforeRev is being copied over starting at location text+offset.
If you were to look at pText on return from call to reverseText you would find it contains:
"Bada boom\0moob adaB"
Your reverseText should be renamed palindrome :)
This is pretty straightforward. Some points to note:
An array decays to a pointer when you pass it to a function.
You are passing in a null terminated string. So the length of the char array you are passing in is the length of the string (including white space) +1.
Because you are using a pointer there is no need to assign a temp variable to hold everything.
Here is some code in C that is easy to translate to C++. Working out the actual reverse algorithm is left for you as an exercise.
#include<stdio.h>
void reverseText(char* text)
{
// Hint: It can be done in one loop!
int i;
for(i = 0; i < 9; i++)
{
// Your algorithm to reverse the text. I'm not doing it for you! ;)
*(text + i) = 'r';
}
}
int main()
{
char array[] = "Bada boom";
reverseText(array);
printf("The text reversed: %s\n", array);
return 0;
}
My final code:
#include <iostream>
void reverseText(char* text){
int length=-1; char tmp;
/*Length = sign from 0 to 8 without counting explicit NUL terminator*/
for(int i=0;*(text+i)!='\0';i++){
length++;
}
int j=0; int i=length;
while(j<i){
tmp=*(text+j); //tmp=first
*(text+j)=*(text+i); //first=last
*(text+i)=tmp; //last=tmp
j++;
i--;
}
}
int main(){
char array[] = "Bada boom";
char *pText = array;
reverseText(pText);
std::cout << pText;
}
I should have read more about pointers before I started this exercise.
You can either return a pointer or pass a pointer to pointer as a function argument.
//pointer to pointer
void reverseText(char** textPtr) {
char* newText = ...; //initialize;
...
*textPtr = newText; //assign newText
}
//return pointer
char* reverseText(char* text) {
char* newText = ...; //initialize
return newText;
}
Remember that if you allocate memory in this function you must do it dynamically (with new or malloc) and you have to free it afterwards (with delete or free respectively). Memory allocation in a function like this is probably a bad practice and should be avoided.
I am trying to implement the functions below, but printing out the output of Printme(), the program that freezes . Any ideas why?
int main()
{
for (int i=0; i<12; i++)
{
cout<< PrintMe()[i];
}
return 0;
}
char * PrintMe() {
char str[12];
strncpy (str, "hello world", 11);
str[11] = 0;
return str;
}
Your code invokes Undefined Behaviour as you are returning a pointer to a temporary.
As soon PrintMe ends its execution, str becomes destroyed. Thus the pointer your accessing with PrintMe()[i] is invalid.
To fix this you have to return a heap allocated string (no automatic storage duration). But dont forget to destroy it afterwards:
char * PrintMe() {
char* str = new char[12];
strncpy (str, "hello world", 11);
str[11] = 0;
return str;
}
char* str = PrintMe();
for (int i=0; i<12; i++)
{
cout<< str[i];
}
delete[] str;
Or as you're writing c++ nontheless, why dont you go with a std::string?
In your PrintMe function, you are returning a pointer to a local variable. This is undefined behavior:
char* PrintMe() {
char str[12];
//...
return str; // cannot do this, UB.
}
This works if you change the return type to std::string
std::string PrintMe() {
char str[12];
//...
return str;
}
The reason why the above now works is that a std::string is being constructed from the local array and returned instead of the local variable.
The program has undefined behaviour because function PrintMe returns a pointer to the first element of a local array that will be destroyed after exiting the function. So the pointer will not be valid.
Change the function the following way that to get the predicted result
char * PrintMe() {
static char str[12];
strncpy (str, "hello world", 11);
str[11] = 0;
return str;
}
Let's say I have a file. I read all the bytes into an unsigned char buffer. From there I'm trying to read a c string (null terminated) without knowing it's length.
I tried the following:
char* Stream::ReadCString()
{
char str[0x10000];
int len = 0;
char* pos = (char*)(this->buffer[this->position]);
while(*pos != 0)
str[len++] = *pos++;
this->position += len+ 1;
return str;
}
I thought I could fill up each char in the str array as I went through, checking if the char was null terminated or not. This is not working. Any help?
this->buffer = array of bytes
this->position = position in the array
Are there any other methods to do this? I guess I could run it by the address of the actual buffer:
str[len++] = *(char*)(this->buffer[this->position++]) ?
Update:
My new function:
char* Stream::ReadCString()
{
this->AdvPosition(strlen((char*)&(this->buffer[this->position])) + 1);
return (char*)&(this->buffer[this->position]);
}
and calling it with:
printf( "String: %s\n", s.ReadCString()); //tried casting to char* as well just outputs blank string
Example File:
Check this:
#include <cstring>
#include <iostream>
class A
{
unsigned char buffer[4096];
int position;
public:
A() : position(0)
{
memset(buffer, 0, 4096);
char *pos = reinterpret_cast<char*>(&(this->buffer[50]));
strcpy(pos, "String");
pos = reinterpret_cast<char*>(&(this->buffer[100]));
strcpy(pos, "An other string");
}
const char *ReadString()
{
if (this->position != 4096)
{
while (std::isalpha(this->buffer[this->position]) == false && this->position != 4096)
this->position++;
if (this->position == 4096)
return 0;
void *tmp = &(this->buffer[this->position]);
char *str = static_cast<char *>(tmp);
this->position += strlen(str);
return (str);
}
return 0;
}
};
The reintrepret_cast are only for the init, since you are reading from a file
int main()
{
A test;
std::cout << test.ReadString() << std::endl;
std::cout << test.ReadString() << std::endl;
std::cout << test.ReadString() << std::endl;
}
http://ideone.com/LcPdFD
Edit I have changed the end of ReadString()
str is a local c string. Any referencing pointer to str outsider the function is undefined behavior: Undefined, unspecified and implementation-defined behavior, it might or might not cause notable problem.
Null termination is probably the best way to go as long as you're careful, but the reason its not working for you is most likely because you are returning memory that has been allocated on the stack. This memory is going to be freed as soon as you hit the return which will therefore cause undefined behaviour. Instead, allocate your chars on the heap:
char* str = new char[0x10000];
and free the memory when the caller doesn't need it anymore.
It can be fixed with the following method. I was advancing the position, and then returning the address.
char* Stream::ReadCString()
{
u64 str_len = strlen((char*)&(this->buffer[this->position])) + 1;
this->AdvPosition(str_len);
return (char*)&(this->buffer[this->position - str_len]);
}
Hope this helps anyone.