How can a conversion from string to char[] make it longer? - c++

I have a problem I cannot really understand how it could exist.
I have a bunch of files ordered by time and containing a bunch of objects. The result should be one file per time ordered in a directory per object.
It works quite fine but at the point where I convert the Outputstring to a char[] to use fstream.open(), the array has 3 characters more than the string has.
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
int main()
{
string strOutput;
char *OutputFile;
short z;
strOutput = "/home/.../2046001_2013-02-25T0959.txt";
cout << strOutput << endl;
OutputFile = new char[strOutput.length()];
z = 0;
while (z < strOutput.length())
{
OutputFile[z] = strOutput[z];
z++;
}
cout << OutputFile << endl;
return 0;
}
The first output is always correct but the second sometimes has the end .txt60A, .txt5.a or .txt9.A.
When it occurs its always the same object and time and it happens every try. But not every object does that.
For obvious reasons I cannot reproduce this error in this minimal code snippet, but I also don't want to post the whole 390 lines of code.
Do you have any suggestions?

You are missing terminating null at the end of C string. To fix:
OutputFile = new char[strOutput.length() + 1]; // notice +1
z = 0;
while (z < strOutput.length())
{
OutputFile[z] = strOutput[z];
z++;
}
OutputFile[z] = 0; // add terminating 0 byte
Of course there are better ways to do the whole thing... you don't really need to copy at all, just get rid of OutputFile and the whole loop, and use the char array inside std::string:
cout << strOutput.c_str() << endl;
I assume the real code wants a C string. std::cout can print std::string directly, of course:
cout << strOutput << endl;
If you actually want to create a copy, it's best to just copy std::string and store that, and use c_str-method to get the C buffer when you need it:
string OutputFile = strOutput;
If you know you really do need a raw char array allocated from heap, you should use std::unique_ptr (or possibly some other C++ smart pointer class) to wrap the pointer, so you do not need to delete manually and avoid memory leaks, and also use standard library function to do copying:
#include <memory>
#include <cstring>
...
unique_ptr<char[]> OutputFile(new char[strOutput.length() + 1];
::strcpy(OutputFile, strOutput.c_str()); // :: means top level namespace

Char arrays need an extra null character or \0 appended to the end, otherwise the code reading the string will run past the end of the array until it finds one.
OutputFile = new char[strOutput.length() + 1];
z = 0;
while (z < strOutput.length())
{
OutputFile[z] = strOutput[z];
z++;
}
OutputFile[z] = '\0';
It may appear to work if the next byte after the array happens to be a null, but that's just a coincidence. I'm sure that's why your code works on the first pass.

at the point where I convert the Outputstring to a char[] to use fstream.open()
You don't have to do that. Do something like this instead:
outfile.open(Outputstring.c_str(), std::fstream::out)
Of course, if you have a C++11-compliant compiler, you can just do:
outfile.open(Outputstring, std::fstream::out)

Related

Returning and Printing Strings in C++

I am trying to get a file path from the user in the getPath() function and return the path as a string. I am having trouble because the compiler says i need to use const char's and i dont know how to do that. How would I use const chars and what even are they. Also how do I print them to the console like in the main function.
#include <iostream>
#include <stdio.h>
#include <string.h>
char getPath() {
char path[64];
std::cout << "Input File Name For Debugging:";
gets(path);
std::cout << "Debugging: ";
puts(path);
return path[64];
}
int main(){
char path[64];
int pathlen = strlen(reinterpret_cast<const char *>(path));
//suppost to print the char array
for(int i; i < pathlen; i++){
std::cout << path[i];
}
return 0;
}
Lot's of misunderstandings
1) char is not a string, it's a character
2) An array of chars (e.g. char [64]) is not a string, its an array. It can hold a string but that's a subtly different idea
3) You don't use [64] when you mean the whole array, so return path[64]; is not the correct way to return a string.
4) Don't mix C++ I/O (std::cin, std::cout) with C I/O (puts, gets), it doesn't work reliably, Stick with C++ I/O so
std::cout << "Debugging: " << path << '\n';
not
std::cout << "Debugging: ";
puts(path);
5) You never call your getPath function so of course it doesn't execute
6) You don't initialise your loop variable i in your final loop so it has no predictable value. You should initialise i to 0
for(int i; i < pathlen; i++){
std::cout << path[i];
should be
for(int i = 0; i < pathlen; i++){
std::cout << path[i];
As you can see lots and lots of mistakes for a very short program. I'm going to show two different correct ways to write this program.
So there are two ways to represent a string in C++, there's the C++ way and there's the way that C++ inherits from C. The code you are writing above is trying to do things the C way, so I'll show that first, but actually the C++ way is much much easier. I'll show that second, but it's the way you should do things.
The first way is to use an array of characters to hold the string. But arrays have serious problems in C++. In particular it's not possible to return an array from a function, so your code above was never going to work, even if you'd fixed all the smaller problems. The way you get C++ to 'return' an array is a bit curious and I'm not going to explain it properly (you need to read a good C++ book). What you do is declare the array in the calling function and pass the array as a parameter. Here's your program written using this technique (and fixed of all the other problems).
#include <iostream>
void getPath(char path[], int n) {
std::cout << "Input File Name For Debugging:";
std::cin.getline(path, n);
std::cout << "Debugging: " << path << '\n';
}
int main(){
char path[64];
getPath(path, 64);
std::cout << path << '\n';
return 0;
}
Note I'm using getline to read the string, which is one C++ way to read a string. getline requires that you pass the size of the array it's going to read into, so I've passed that to getPath as well as the array itself.
Now for the easy way. C++ has it's own string type called std::string. You don't need to use tricky arrays at all. And the C++ string type can be returned from a function in the normal way. This makes for much more natural code. To use the C++ string type all you need to do is #include <string>. Here's your program rewritten to use the C++ string type
#include <iostream>
#include <string>
std::string getPath() {
std::cout << "Input File Name For Debugging:";
std::string path;
std::getline(std::cin, path);
std::cout << "Debugging: " << path << '\n';
return path;
}
int main(){
std::string path;
path = getPath();
std::cout << path << '\n';
return 0;
}
Notice this second program is closer to your original code, getPath has a return type, only it's std::string not char, and it has a return statement to return the path. This is the way you should be writing this code, the C++ string type will make writing string code much easier for you.

How do I combine two strings?

The question requires combining two strings(the longer string in the front and the shorter one after the longer one) without using <string> header file.Each string inputted can't exceed 20 characters.
My logic behind this is:
first use strlen to get the length of the str1 and str2,
use str3 to store the longer string, and str4 to store the shorter.
add str3 and str4 to str5
Here is my code:
#include<iostream>
using namespace std;
int main()
{
// combine two strings , longer in the front, and shorter
// after it. do not use strcat
char str1[20],str2[20],str3[20],str4[20],str5[40];
// str1 and str2 stores original data, str3 stores longer
// and str4 stores shorter, str5 stores total
int j=0;
cin.getline(str1,20);
cin.getline(str2,20);
if(strlen(str1)<=strlen(str2))
// give longer string value to str3,shorter to str2
{
for (int i=0;i<20;i++)
{
str3[i]=str2[i];
str4[i]=str1[i];
}
}
else
{
for (int i=0;i<20;i++)
{
str3[i]=str1[i];
str4[i]=str2[i];
}
}
for(j=0;str3[j]!='\0';j++)
{
str5[j]=str3[j];
}
for(int i=j;i<40;i++)
for(int m=0;m<20;m++)
{
str5[i]=str4[m];
}
cout<<str5<<endl;
return 0;
}
Here is the ouput:
What's my problem here? What are those characters in between the two strings? Thank you!!
Especially since you explicitly mentioned being a beginner, the solution is to use std::string:
#include <iostream>
#include <string>
int main() {
std::string a;
getline(std::cin, a);
std::string b;
getline(std::cin, b);
// Ensure that the longer string goes to the front.
if (a.size() < b.size());
swap(a, b);
std::string result = a + b;
std::cout << result << '\n';
// Or, simply:
std::cout << a << b << '\n';
}
The message here is that C++, despite its quirks, is a very high level language if you rely on its library instead of implementing every low level operation from scratch.
Everything is fine (!) up to this point
for(int i=j;i<40;i++)
for(int m=0;m<20;m++) // This loop runs m=0 to 20 for each position of i
{
str5[i]=str4[m];
}
For each index i you are copying in all 20 elements from str4, leaving just the value at str4[19] which could be anything
Just increment i and m by one together
int m = 0;
for(int i=j;i<40;i++)
{
str5[i]=str4[m++];
}
You are copying the entire 20 characters, 40 characters in the loop into the variables. stop copying when you find a '\0' character.
But using the std::string will make life simpler :)
Using std::string is nice and all but here's a few tips for working with char*:
1) You shouldn't copy strings to separate shorter and longer string, just use pointers and then work with these pointers, something along these lines:
const char *longer_string = 0, *shorter_string = 0;
if(strlen(str1)<=strlen(str2))
{
shorter_string = str1;
longer_string = str2;
}
else
{
shorter_string = str2;
storter_string = str1;
}
2) Using strcpy and strcat to combine strings could make life a lot easier:
char *combined_string = new char [strlen (shorter_string) + strlen (longer_string) + 1];
strcpy (combined_string, longer_string);
strcat (combined_string, shorter_string);
Some compilers would say that these functions aren't safe and you have to stick to _s versions, but I guess it's entirely up to you.
Since this is obviously homework: I'll just point out the existence of the function strcat, and the fact that you can use char* to the arrays, and just swap them, without having to recopy anything between the initial read and the concatenation (which means that you only need two arrays: one for each of the inputs, and one for the final value).
And also, when calculating sizes, etc. do not forget that C style strings have an extra '\0' at the end, and make allowances for it.
As #David Sykes has pointed out, the problem is with your for loop. So when you read input from cin ,it is not necessary that your input string contains 20 character. But in you form loop you are looping through those string beyond their length which may contains garbage characters. Example
char str1[20]
cin.getline(str1,20);
cout << str1[19] << endl;
Suppose your input for above code is "ABCD" which contains only 4 characters but your array has capacity of 20. So the remaining space has junk characters and when you will try to print any thing beyond actual length you will get wild character as you are getting in your code.

passing array as parameter to a function

this script is supposed to output array values that were inputted by the user into array "store." I am trying to store all the char array values into string temp. I get the error on line 12: "[Error] invalid conversion from 'char*' to 'char' [-fpermissive]." Would appreciate any help!
Edit: so I fixed the declaration and now at least it compiles, but the answer I get on my cmd is all jumbled up. Why is this so? The cmd only correctly couts the first string but after the space, it messes up.
#include <iostream>
#include <cstdlib>
using namespace std;
void coutArray(char[], int);
int main()
{
char store[50];
cout << "enter text: " << endl;
cin >> store;
coutArray(store, 50);
system("pause");
return 0;
}
void coutArray(char store[], int max)
{
string temp = "";
int i = 0;
while (i < max)
{
temp += store[i];
i++;
}
cout << temp << endl;
}
Using input from all answerers I finally got the fixed code:
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;
void coutArray(char[], int);
int main()
{
char store[50] = {0};
cout << "enter text: " << endl;
cin.getline(store, 50);
coutArray(store, 50);
system("pause");
return 0;
}
void coutArray(char store[], int max)
{
string temp = "";
int i = 0;
while (i < max && store[i]!=0)
{
temp += store[i];
i++;
}
cout << temp << endl;
}
Thanks everyone. i learned a lot!!!
When you get an input using "cin" your input automatically ends with 0 (NULL).
You just need to add one little piece of code to your while statement.
instead of this :
while (i < max)
use this :
while (i < max && store[i]!=0)
Now it will stop when the input string is finished and won't print any garbage existed in the array beforehand.
To show that cin does add terminating zero, i initialized the array to 46, and put a breakpoint after the cin
so I fixed the declaration and now at least it compiles, but the answer I get on my cmd is all jumbled up. Why is this so?
Not sure what you mean by jumbled up. But since you did not tell us what you typed its hard to know it looks like it worked to me:
> ./a.out
enter text:
Plop
Plop�ȏU�
Notice that since my input is only 4 characters long. This means that a lot of the characters in the array still have undefined (ie random values). This is why I am seeing junk. To get past this initialize the array to have all 0 values.
char store[50] = {0};
Even bettern use a C++ object than handles longer strings.
std::string store;
std::getline(std::cin, store);
Note: passing arrays to functions by value is not a good idea. On the other end they have decayed to pointers and thus do not act like arrays anymore (they act like pointers whose semantics are similar but not identical).
If you must pass an array pass it by reference. But I would use a C++ container and pass that by reference (it is much safer than using C constructs). Have a look at std::string
The declaration of the function is wrong. Should be void coutArray(char *, int);
Look at the Implicit Conversion rules to understand what the compiler can do and what it cannot to do for you.
The issue with your program was that you were probably entering in less characters than the maximum size of the buffer. Then when you passed the maximum size as the parameter to coutArray, you assigned unfilled slots in the char array to temp. These unfilled slots could contain anything, as you have not filled them up to that point.
Your program is still correct, but what would be better would be to use read so that the number of bytes you specify is the minimum number of bytes that can be entered:
std::cin.read(store, 50);
Even better solution would be to use std::string:
std::string store;
std::cin >> store;
// or for the entire line
std::getline(std::cin, store);
It also follows that your coutArray should be changed to:
void coutArray(std::string);
// ...
void coutArray(std::string str)
{
std::cout << str << std::endl;
}
Look at this way
template<typename T, size_t N>
void MyMethod(T (&myArray)[N])
{
//N is number of elements, myArray is the array
std::cout<<"array elements number = "<<N<<endl;
//put your code
string temp;
temp.resize(N+1);//this is for performance not to copy it each time you use += operator
int i = 0;
while (i < max)
{
temp += store[i];
i++;
}
cout << temp << endl;
}
//call it like this
char arr[] = "hello world";
MyMethod(arr);

weird output when printing data of custom string (c++ newbie)

my main concern is if i am doing this safely, efficiently, and for the most part doing it right.
i need a bit of help writing my implementation of a string class. perhaps someone could help me with what i would like to know?
i am attempting to write my own string class for extended functionality and for learning purposes. i will not use this as a substitute for std::string because that could be potentially dangerous. :-P
when i use std::cout to print out the contents of my string, i get some unexpected output, and i think i know why, but i am not really sure. i narrowed it down to my assign function because any other way i store characters in the string works quite fine. here is my assign function:
void String::assign(const String &s)
{
unsigned bytes = s.length() + 1;
// if there is enough unused space for this assignment
if (res_ >= bytes)
{
strncpy(data_, s.c_str(), s.length()); // use that space
res_ -= bytes;
}
else
{
// allocate enough space for this assignment
data_ = new char[bytes];
strcpy(data_, s.c_str()); // copy over
}
len_ = s.length(); // optimize the length
}
i have a constructor that reserves a fixed amount of bytes for the char ptr to allocate and hold. it is declared like so:
explicit String(unsigned /*rbytes*/);
the res_ variable simply records the passed in amount of bytes and stores it. this is the constructor's code within string.cpp:
String::String(unsigned rbytes)
{
data_ = new char[rbytes];
len_ = 0;
res_ = rbytes;
}
i thought using this method would be a bit more efficient rather than allocating new space for the string. so i can just use whatever spaced i reserved initially when i declared a new string. here is how i am testing to see if it works:
#include <iostream>
#include "./string.hpp"
int main(int argc, char **argv)
{
winks::String s2(winks::String::to_string("hello"));
winks::String s(10);
std::cout << s2.c_str() << "\n" << std::endl;
std::cout << s.unused() << std::endl;
std::cout << s.c_str() << std::endl;
std::cout << s.length() << std::endl;
s.assign(winks::String::to_string("hello")); // Assign s to "hello".
std::cout << s.unused() << std::endl;
std::cout << s.c_str() << std::endl;
std::cout << s.length() << std::endl;
std::cout.flush();
std::cin.ignore();
return 0;
}
if you are concerned about winks::String::to_string, i am simply converting a char ptr to my string object like so:
String String::to_string(const char *c_s)
{
String temp = c_s;
return temp;
}
however, the constructor i use in this method is private, so i am forcing to_string upon myself. i have had no problems with this so far. the reason why i made this is to avoid rewriting methods for different parameters ie: char * and String
the code for the private constructor:
String::String(const char *c_s)
{
unsigned t_len = strlen(c_s);
data_ = new char[t_len + 1];
len_ = t_len;
res_ = 0;
strcpy(data_, c_s);
}
all help is greatly appreciated. if i have no supplied an efficient amount of information please notify me with what you want to know and i will gladly edit my post.
edit: the reason why i am not posting the full string.hpp and string.cpp is because it is rather large and i am not sure if you guys would like that.
You have to make a decision whether you will always store your strings internally terminated with a 0. If you don't store your strings with a terminating zero byte, your c_str function has to add one. Otherwise, it's not returning a C-string.
Your assign function doesn't 0 terminate. So either it's broken, or you didn't intend to 0 terminate. If the former, fix it. If the latter, check your c_str function to make sure it puts a 0 on the end.

How to get the size of the used space in an array? (NOT sizeof); c++

#include<iostream>
using namespace std;
int main()
{
char arr[200];
while(1) {
cin >> arr;
int i = sizeof(arr);
cout << "The arr input is "<< arr
<< " and the size of the array is "<< i << endl;
}
return 0;
}
For the input of 34,
This code outputs :The arr input is 34 and the size of the array is 200
while I want it to get the size of the used space of the array . So for The last input i want it to output :The arr input is 34 and the size of the array is 2
Can someone tell me how?
Maybe you want strlen(arr) here. It must be null terminated, otherwise the cout << arr would not have worked.
You would need to #include <cstring>
There's no automatic way to do what you want in the general case - you'll need to keep track somehow, either with your own counter, or by seeding the array with an 'invalid' value (that you define) and search for to find the end of the used elements (that's what the '\0' terminator character in a C-style string is).
In the example code you posted, the array should receive a null terminated C-style string, you can use that knowledge to count the number of valid elements.
If you're using C++ or some other library that has some more advanced data structures, you may be able to use one that keeps track of this kind of thing for you (like std::vector<>).
the size of the used space of the array
There is no such thing. If you have an array of 200 chars, then you have 200 chars. Arrays have no concept of "used" and "unused" space. It only works with C-strings because of the convention that those are terminated by a 0 character. But then again, the array itself cannot know if it is holding a C-string.
in a less involved manner, you can just count through each character till you hit a null with just a while loop. It will do the exact same thing strlen() does. Also, in practice, you should do type checking with cin, but i'll assume this was just a test.
#include <iostream>
using namespace std;
int main()
{
char arr[200];
int i;
while(1) {
cin >> arr;
i=0;
while (arr[i] != '\0' && i<sizeof(arr))
i++;
cout << "The arr input is "<< arr
<< " and the size of the array is "<< i << endl;
}
return 0;
}
Just for completeness, here is a much more C++ like solution that is using std::string instead of a raw char array.
#include <iostream>
#include <string>
int
main()
{
while (std::cin.good()) {
std::string s;
if (std::cin >> s) {
std::cout
<< "The input is " << s
<< " and the size is " << s.length()
<< std::endl;
}
}
return 0;
}
It doesn't use an array, but it is the preferable solution for this kind of problem. In general, you should try to replace raw arrays with std::string and std::vector as appropriate, raw pointers with shared_ptr (scoped_ptr, or shared_array, whatever is most appropriate), and snprintf with std::stringstream. This is the first step to simply writing better C++. You will thank yourself in the future. I wish that I had followed this advice a few years ago.
Try it
template < typename T, unsigned N >
unsigned sizeOfArray( T const (&array)[ N ] )
{
return N;
}