string to character conversion error? - c++

After trying for about 1 hour, my code didn't work because of this:
void s_s(string const& s, char data[10])
{
for (int i = 0; i < 10; i++)
data[i] = s[i];
}
int main()
{
string ss = "1234567890";
char data[10];
s_s("1234567890", data);
cout << data << endl;//why junk
}
I simply don't understand why the cout displays junk after the char array. Can someone please explain why and how to solve it?

You need to null terminate your char array.
std::cout.operator<<(char*) uses \0 to know where to stop.
Your char[] decays to char* by the way.
Look here.

As already mentioned you want to NUL terminate your array, but here's something else to consider:
If s is your source string, then you want to loop to s.size(), so that you don't loop past the size of your source string.
void s_s(std::string const& s, char data[20])
{
for (unsigned int i = 0; i < s.size(); i++)
data[i] = s[i];
data[s.size()] = '\0';
}
Alternatively, you can try this:
std::copy(ss.begin(), ss.begin()+ss.size(),
data);
data[ss.size()] = '\0';
std::cout << data << std::endl;

You have ONLY allocated 10 bytes for data
The string is actually 11 bytes since there is an implied '\0' at the end
At a minimum you should increase the size of data to 11, and change your loop to copy the '\0' as well

The function std::ostream::operator<< that you are trying to use in the last line of the main will take your char array as a pointer and will print every char until the null sentinel character is found (the character is \0).
This sentinel character is generally generated for you in statements where a C-string literal is defined:
char s[] = "123";
In the above example sizeof(s) is 4 because the actual characters stored are:
'1', '2', '3', '\0'
The last character is fundamental in tasks that require to loop on every char of a const char* string, because the condition for the loop to terminate, is that the \0 must be read.
In your example the "junk" that you see are the bytes following the 0 char byte in the memory (interpreted as char). This behavior is clearly undefined and can potentially lead the program to crash.
One solution is to obviously add the \0 char at the end of the char array (of course fixing the size).
The best solution, though, is to never use const char* for strings at all. You are correctly using std::string in your example, which will prevent this kind of problems and many others.
If you ever need a const char* (for C APIs for example) you can always use std::string::c_str and retrieve the C string version of the std::string.
Your example could be rewritten to:
int main(int, char*[]) {
std::string ss = "1234567890";
const char* data = ss.c_str();
std::cout << data << std::endl;
}
(in this particular instance, a version of std::ostream::operator<< that takes a std::string is already defined, so you don't even need data at all)

Related

Why can't I call my function recursively?

I'm trying to compile this code in order to reverse a string:
void reverse(char *str, int n)
{
if (n==0 || n==1) {
return; //acts as quit
} else {
char i = str[0]; //1st position of string
char j = str[n-1]; //Last position of string
char temp = str[i];
str[i] = str[j]; //Swap
str[j] = temp;
reverse(str[i+1],n-1); // <-- this line
}
}
#include <iostream>
int main()
{
char *word = "hello";
int n = sizeof word;
reverse(word, n);
std::cout << word << std::endl;
return 0;
}
The compiler reports an error where I call reverse() recursively:
invalid conversion from char to char* at reverse(str[i+1], n-1).
Why?
Any advice on other issues in my code is also welcome.
str[i+1] is a character, not a pointer to a character; hence the error message.
When you enter the function, str points to the character you're going to swap with the n:th character away from str.
What you need to do in the recursion is to increment the pointer so it points to the next character.
You also need to decrease n by two, because it should be a distance from str + 1, not from str.
(This is easy to get wrong; see the edit history of this answer for an example.)
You're also using the characters in the strings as indexes into the strings when swapping.
(If you had the input "ab", you would do char temp = str['a']; str['a'] = str['b']; str['b'] = temp;. This is obviously not correct.)
str[0] is not the position of the first character, it is the first character.
Use std::swap if you're allowed to, otherwise see below.
More issues: you shouldn't use sizeof word, as that is either 4 or 8 depending your target architecture - it's equivalent to sizeof(char*).
You should use strlen to find out how long a string is.
Further, you should get a warning for
char *word = "hello";
as that particular conversion is dangerous - "hello" is a const array and modifying it is undefined.
(It would be safe if you never modified the array, but you are, so it isn't.)
Copy it into a non-const array instead:
char word[] = "hello";
and increase the warning level of your compiler.
Here's a fixed version:
void reverse(char *str, int n)
{
if(n <= 1) // Play it safe even with negative n
{
return;
}
else
{
// You could replace this with std::swap(str[0], str[n-1])
char temp = str[0]; //1st character in the string
str[0] = str[n-1]; //Swap
str[n-1] = temp;
// n - 2 is one step closer to str + 1 than n is to str.
reverse(str + 1, n - 2);
}
}
int main()
{
char word[] = "hello";
// sizeof would actually work here, but it's fragile so I prefer strlen.
reverse(word, strlen(word));
std::cout << word << std::endl;
}
I'm going to dissect your code, as if you'd posted over on Code Review. You did ask for other observations, after all...
Firstly,
char *word = "hello";
Your compiler should warn you that pointing a char* at a literal string is undefined behaviour (if not, make sure that you have actually enabled a good set of warnings. Many compilers emit very few warnings by default, for historical reasons). You need to ensure that you have a writable string; for that you can use a char[]:
char word[] = "hello";
The next line
int n = sizeof word;
has now changed meaning, but is still wrong. In your original code, it was the size of a pointer to char, which is unlikely to be the same as the length of the word "hello". With the change to char[], it's now the size of an array of 6 characters, i.e. 6. The sixth character is the NUL that ends the string literal. Instead of the sizeof operator, you probably want to use the strlen() function.
Moving on to reverse():
You read characters from positions in the string, and then use those characters to index it. That's not what you want, and GCC warns against indexing using plain char as it may be signed or unsigned. You just want to index in one place, and your i and j are unnecessary.
Finally, the question you asked. str[i+1] is the character at position i+1, but your function wants a pointer to character, which is simply str+i+1. Or, since we worked out we don't want i in there, just str+1.
Note also that you'll need to subtract 2 from n, not 1, as it will be used as a count of characters from str+1. If you only subtract 1, you'll always be swapping with the last character, and you'll achieve a 'roll' rather than a 'reverse'.
Here's a working version:
void reverse(char *str, int n)
{
if (n < 2)
// end of recursion
return; //acts as quit
char temp = str[0];
str[0] = str[n-1]; //Swap
str[n-1] = temp;
reverse(str+1,n-2);
}
#include <iostream>
#include <cstring>
int main()
{
char word[] = "hello";
int n = std::strlen(word);
reverse(word, n);
std::cout << word << std::endl;
}
We can make further changes. For example, we could use std::swap to express the switching more clearly. And we could pass a pair of pointers instead of a pointer and a length:
#include <utility> // assuming C++11 - else <algorithm>
void reverse(char *str, char *end)
{
if (end <= str)
// end of recursion
return;
std::swap(*str, *end);
reverse(str+1, end-1);
}
and invoke it with reverse(word, word+n-1).
Finally (as I'm not going to mention std::reverse()), here's the idiomatic iterative version:
void reverse(char *str, char *end)
{
while (str < end)
std::swap(*str++, *end--);
}
use like this :
reverse(&str[i+1],n-1);
pass address of the (i+1)th position not value.

Grabbing a portion of a string like substr

So I'm making a function that is similar to SubStr. This is an assignment so I cannot use the actual function to do this. So far I have created a function to take a string and then get the desired substring. My problem is returning the substring. In the function when I do Substring[b] = AString[b]; the substring is empty, but if I cout from inside the function I get the desired substring. So what is wrong with my code?
Here is a working demo: http://ideone.com/4f5IpA
#include <iostream>
using namespace std;
void subsec(char AString[], char Substring[], int start, int length);
int main() {
char someString[] = "abcdefg";
char someSubString[] = "";
subsec(someString, someSubString, 1, 3);
cout << someSubString << endl;
return 0;
}
void subsec(char AString[], char Substring[], int start, int length) {
for (int b = start; b <= length; b++) {
Substring[b] = AString[b];
}
}
Maybe this does what you're looking for? It's hard to say as your initial implementation used the length parameter as more of an end position.
#include <iostream>
using namespace std;
void subsec(char AString[], char Substring[], int start, int length)
{
const int end = start + length;
int pos = 0;
for(int b = start; b < end; ++b)
{
Substring[pos++] = AString[b];
}
Substring[pos] = 0;
}
int main()
{
char someString[50] = "abcdefghijklmnopqrstuvwxyz";
char someSubString[50];
subsec(someString, someSubString, 13, 10);
cout << someSubString << endl;
return 0;
}
There are several problems with the code:
1) The char arraysomeSubString has size 1 which cannot hold the substring.
2) The subsec is not correctly implemented, you should copy to the Substring from index 0.
Also remember to add \0 at the end of the substring.
void subsec(char AString[], char *Substring, int start, int length) {
int ii = 0;
for (int jj = start; jj <= length; jj++, ii++) {
Substring[ii] = AString[jj];
}
Substring[ii] = '\0';
}
You need to allocate more than 1 byte for someSubString i.e.
char someSubString[] = "xxxxxxxxxxxxxxxxxx";
or just
char someSubString[100];
if you know the max size you'll ever need.
Either would allocate enough space for the string you're copying to it. Then, you're not doing anything about the terminating 0 either. At the end of a C-style string there needs to be a terminating null to signify end of string. Otherwise cout will print something like;
abcdefgxxxxxxx
if you initialized with x's as I indicated.
There are a few problems with your code as it stands. Firstly, as your compiler is no doubt warning you, in C++ a string literal has type const char[], not just char[].
Secondly, you need to have enough space to store your substring. A good way to do this is for your function to allocate the space it needs, and then pass back a pointer to this memory. This is the way things are typically done in C code. The only thing is that you have to remember to delete the allocated array when you're done with it. (There are other, better ways to do this in C++, with things like smart pointers and wrapper objects, but those come later :-) ).
Thirdly, you'll have a problem if you request a length which is actually longer than the passed-in string -- you'll run off the end and start copying random memory (or just crash), which is definitely not what you want. C strings are terminated with a "nul byte" -- so you need to check whether you've come across this.
Speaking of the nul, you need to make sure that your substring ends with one.
Lastly, it's not really a problem but there's no need for the start parameter, you can just pass a pointer to the middle of the array if you want to.
char* substring(const char* str, int length)
{
// Allocate memory for substring;
char* subs = new char[length+1];
// Copy characters from given string
int i = 0;
while (i < length && str[i] != '\0') {
subs[i] = str[i];
i++;
}
// Append the nul byte
subs[i] = '\0';
return subs;
}
int main()
{
const char someString[] = "foobarbaz"; // Note -- must be const in C++
char* subs = substring(someString + 3, 3);
assert(strcmp(subs, "bar") == 0);
delete subs;
}

Counting Bytes Of Char S

I have a homework, It is:
Write the code of function below, this function should count number of bytes inside of s till it is not '\0'.
The function:
unsigned len(const char* s);
Really I do not know what this homework mean, can anyone write this homework's code please?
Further more can anyone please explain what does "Const char* s" mean? If you can explain with some examples it would be perfect.
Here is a code which I'm trying to do:
unsigned len(const char* s)
{
int count=0;; int i=0;
while (*(s+i)!=0)
{
count++;
i++;
}
return count;
}
But in the main function I do not know what should I write, BTW I have written this:
const char k='m';
const char* s=&k;
cout << len(s) << endl;
The result always is 4! really I do not know what should I do for this question, if I can store only one character in const char, so the result should be the same always. What this question is looking for exactly?
The homework means you should write a function that behaves like this:
int main() {
char s[] = {'a','b','c','\0'};
unsigned s_length = len(s);
// s_length will be equal to 3 ('a','b','c', not counting '\0')
}
I think it's unlikely that anyone will do you homework for you here.
Presumably your class has covered function parameters, pointers, and arrays if you're being asked to do this. So I guess you're asking about const. const char* s means that s points to a const char, which means you're not allowed to modify the char. That is, the following is illegal:
unsigned len(const char *s) {
*s = 'a'; // error, modifying a const char.
}
Here are the basic things you need to know about pointers to write the function. First, in this case the pointer is pointing at an element in an array. That is:
char A[] = {'a','b','c','\0'};
char const *s = &A[0]; // s = the address of A[0];
The pointer points to, or references, a char. To get that char you dereference the pointer:
char c = *s;
// c is now equal to A[0]
Because s points at an element of an array, you can add to and subtract from the pointer to access other elements of the array:
const char *t = s+1; // t points to the element after the one s points to.
char d = *t; // d equals A[1] (because s points to A[0])
You can also use the array index operator:
char c = s[0]; // c == A[0]
c = s[1]; // c == A[1]
c = s[2]; // c == A[2]
What would you used to look at each element of the array sequentially, with an increasing index?
Your proposed solution looks like it should work correctly. The reason you're getting a result of 4 is just coincidence. You could be getting any results at all. The problem with the way you're calling the function:
const char k='m';
const char* s=&k;
cout << len(s) << endl;
is that there's no '\0' guaranteed to be at the end. You need to make an array where one of the elements is 0:
const char k[] = { 1,2,3,0};
const char* s = &k[0];
cout << len(s) << '\n'; // prints 3
char m[] = { 'a', 'b', 'c', 'd', '\0', 'e', 'f'};
cout << len(m) << '\n'; // prints 4
char const *j = "Hello"; // automatically inserts a '\0' at the end
cout << len(j) << '\n'; // prints 5
In C (and by extension C++), strings can be represented as a sequence of characters terminated by a null character. So, the string "abc" would be represented as
'a', 'b', 'c', '\0'
This means, you can get the length of a C string by counting each character until you encounter a null. So if you have a null terminated const char* string, you can find out the length of that string by looping over the string and incrementing a counter variable until you find the '\0' character.
it means you have a string like hello world Every string terminates with a \0. That means it looks like this: hello world\0
Now step over the char array (char* s) until you find \0.
Update:
\0 is in fact only one single character of value 0x00. \ is used to tell visualize that this is meant instead of the number 0 in a string.
Example:
0abc\0 -> string starting with number 0 and is terminated with 0x0.
EDIT
char * indicates the type of the variable s. It is a pointer to a character array. const means that this character array is readonly and can't be changed.
Do you actually mean "count the characters till you find a '\0'"?
If so, you could implement it like this:
for each character
if it is not 0
increment x (where x is variable holding number of characters found)
otherwise
stop looking
return x
I am not going to write your homework as well :P, but let me give you some hint: it's called "pointer arithmetic". So, a pointer is a thing exactly just as it names says: a pointer to a memory "cell". As you know all variables in the memory are stored in "cells", that you can refer by an address. A C string is stored in continuous cells in the memory, so for example "abc" would look like something like (the '\0' is added by the compiler when you define a string literal with quotes):
+----+----+----+----+
|'a' |'b' |'c' |'\0'|
+----+----+----+----+
^
s
and you also get the address of the first char. Now, to get the address of 'b', you can simple add one to s like this: (s + 1). To get what is actually in the cell where s points to, you should use the * operator:
*s = 'a' or *(s + 1) = 'b'. This is called pointer arithmetic.
Note: in this case adding one to the pointer shifts to the next cell, because char is one byte long. If you define a pointer to bigger structure (long int for example of 4 bytes) adding one will move to the to the position in the memory where your next structure would begin (in case of long int it will move +4 bytes).
Now that should be enough help to finish your hw.
OK , I have found my answer, just check if I'm true:
#include <iostream>
using namespace std;
unsigned len(const char*);
int main()
{
const char* s = "Hello";
cout << len(s) << endl;
return 0;
}
unsigned len(const char* s)
{
int count=0;; int i=0;
while (*(s+i)!=0)
{
count++;
i++;
}
return count;
}
So it is showing that I have set "Hello" into const char* s; So for const char* variables I should use strings like "Hello" with the sign ("). Is that True?

Convert non-null-terminated char* to int

I am working on some code that reads in a data file. The file frequently contains numeric values of various lengths encoded in ASCII that I need to convert to integers. The problem is that they are not null-terminated, which of course causes problems with atoi. The solution I have been using is to manually append a null to the character sequence, and then convert it.
This is the code that I have been using; it works fine, but it seems very kludgy.
char *append_null(const char *chars, const int size)
{
char *tmp = new char[size + 2];
memcpy(tmp, chars, size);
tmp[size + 1] = '\0';
return tmp;
}
int atoi2(const char *chars, const int size)
{
char *tmp = append_null(chars, size);
int result = atoi(tmp);
delete[] tmp;
return result;
}
int main()
{
char *test = new char[20];
test[0] = '1';
test[1] = '2';
test[2] = '3';
test[3] = '4';
cout << atoi2(test, 4) << endl;
}
I am wondering if there is a better way to approach this problem.
Fixed-format integer conversion is still well within handroll range where the library won't do:
size_t mem_tozd_rjzf(const char *buf, size_t len) // digits only
{
int n=0;
while (len--)
n = n*10 + *buf++ - '0';
return n;
}
long mem_told(const char *buf, size_t len) // spaces, sign, digits
{
long n=0, sign=1;
while ( len && isspace(*buf) )
--len, ++buf;
if ( len ) switch(*buf) {
case '-': sign=-1; \
case '+': --len, ++buf;
}
while ( len-- && isdigit(*buf) )
n = n*10 + *buf++ -'0';
return n*sign;
}
In C++11, you can say std::stoi(std::string(chars, size)), all from <string>.
int i = atoi(std::string(chars, size).c_str());
Your method will work, although you should only need size+1 for appending the null and the null will go at position size. Currently, your test code doesn't actually make the function call, but I'll assume that you have a way to determine when the null-terminated characters end. If possibly, I'd recommend making the null termination there so that you don't have to worry about catching cases where you hit an exception before you can deallocate the memory (memory which, honestly, may or may not have been allocated if you start catching exceptions).
std::string str = "1234";
boost::lexical_cast<int>(str); // 1234
The problem as formulated requires to construct a string given an array of known size, then converting its text into a numeric value.
To convert text into values, C++ has a unified mechanism: streams.
In your case, you can do the following:
int i = 0;
std::stringstream(std::string(yourbuffer, yoursize)) >> i;
This will completely avoid any plain old C reference.
But, since -as you say- all values come from a file... why just don't read the file itself as a stream via std::fstream ?
The question says (emph mine):
The file frequently contains numeric values of various lengths encoded
in ASCII that I need to convert to integers. The problem is that they
are not null-terminated, which of course causes problems with atoi.
This does not really pose a problem, as, if we look at the docs for atoi or strtol, they clearly state:
Function discards any whitespace characters until first non-whitespace
character is found. Then it takes as many characters as possible to
form a valid integer number representation and converts them to
integer value.
That means, it doesn't matter at all that the numbers aren't null terminated, as long as they are delimited by something that stops conversion.
And if they are not delimited, then you have to know the size, and when you know the size, I would also recommend a hand-coded solution like in the other answer.
I know this answer is not answering OP's question, but it helps if your source of char* is a char array with known size.
Live demo
#include <fmt/core.h>
#include <type_traits>
#include <iostream>
// SFINAE fallback
template<typename T, typename =
std::enable_if< std::is_pointer<T>::value >
>
int charArrayToInt(const T arr){ // Fall back for user friendly compiler errors
static_assert(false == std::is_pointer<T>::value, "`charArrayToInt()` dosen't allow conversion from pointer!");
return -1;
}
// Valid for both null or non-null-terminated char array
template<size_t sz>
int charArrayToInt(const char(&arr)[sz]){
// It doesn't matter whether it's null terminated or not
std::string str(arr, sz);
return std::stof(str);
}
int main() {
char number[2] = {'4','2'};
int ret = charArrayToInt(number);
fmt::print("The answer is {}. ", ret);
return 0;
}

invalid conversion from 'char' to 'char*' using strcpy

Ok so here are the parts of my code that I'm having trouble with:
char * historyArray;
historyArray = new char [20];
//get input
cin.getline(readBuffer, 512);
cout << readBuffer <<endl;
//save to history
for(int i = 20; i > 0; i--){
strcpy(historyArray[i], historyArray[i-1]); //ERROR HERE//
}
strcpy(historyArray[0], readBuffer); //and here but it's the same error//
The error that i'm receiving is:
"invalid conversion from 'char' to 'char*'
initializing argument 1 of 'char* strcpy(char*, const char*)'
The project is to create a psudo OS Shell that will catch and handle interrupts as well as run basic unix commands. The issue that I'm having is that I must store the past 20 commands into a character array that is dynamically allocated on the stack. (And also de-allocated)
When I just use a 2d character array the above code works fine:
char historyArray[20][];
but the problem is that it's not dynamic...
And yes I do know that strcpy is supposed to be used to copy strings.
Any help would be greatly appreciated!
historyArray points to (the first element of) an array of 20 chars. You can only store one string in that array.
In C, you could create a char** object and have it point to the first element of an array of char* objects, where each element points to a string. This is what the argv argument to main() does.
But since you're using C++, it makes a lot more sense to use a vector of strings and let the library do the memory management for you.
Stop using C idioms in a C++ program:
std::deque<std::string> historyArray;
//get input
std::string readBuffer;
std::getline(std::cin, readBuffer);
std::cout << readBuffer << std::endl;
//save to history
historyArray.push_front(readBuffer);
if(historyArray.size() > 20)
historyArray.pop_back();
As a result, we have:
No buffer-overflow threat in readBuffer / getline()
No pointers, anywhere, to confuse us.
No arrays to overstep the ends of
Arbitrarily long input strings
Trivially-proven memory allocation semantics
Two solutions. The first is if you for some reason really want arrays, the other is more recommended and more "C++"ish using std::strings.
char * historyArray[20]; // Create an array of char pointers
// ...
historyArray[i] = new char[SIZE]; // Do this for each element in historyArray
Then you can use strcpy on the elements in historyArray.
Second solution which I repeat is recommended (I've fixed a few other things):
string historyArray[20];
getline(cin, readBuffer); // Make readbuffer an std::string as well
cout << readBuffer << endl;
for(int i = 19; i > 0; i--){ // I think you meant 19 instead of 20
historyArray[i] = historyArray[i-1];
}
historyArray[0] = readBuffer;
historyArray[i] is a char. It is a single character. You want to use a sting. Your fundemental problem is that historyArray is a char* which means that it points to a memory range containing characters. You want it to be a char** which is a pointer to a pointer to a string. Your initialization code would be
char** historyArray;
historyArray = new char* [20];
for (int i = 0; i < 20; i++)
{
historyArray[i] = new char [512]; //Big enough to have a 512 char buffer copied in
}
Error 1: You're indexing past your array bounds with i being set to 20.
Error 2: historyArray[i] is a char, not a char *. You need &historyArray[i].
strcpy(&historyArray[i], &historyArray[i-1]);
Array notation gives references while strcopy wants pointers. Convert references to pointers with address-of (&) operator.
char * historyArray;
historyArray = new char [20];
//get input
cin.getline(readBuffer, 512);
cout << readBuffer <<endl;
//save to history
for(int i = 20; i > 0; i--){
strcpy(&(historyArray[i]), &(historyArray[i-1])); //ERROR HERE//
}
strcpy(historyArray, readBuffer); //and here but it's the same error//
But that will only fix the compiler errors, not the logical errors in the code. Your using C++ so the string solution:
vector<string> history;
cin.getline(readBuffer,512);
history.push_back(readBuffer);
Alternatively if you want one long string containing everything from readBuffer:
string history;
cin.getline(readBuffer,512);
history = history += string(readBuffer);
For example...