Answers to Why this program compiles fine in C & not in C++? explain that unlike the C language, the C++ language does not tolerate an initializer string for a char array that is not long enough to hold the terminating null character. Is there a way to specify an unterminated char array in C++ without bloating the string by a factor of four in the source code?
For example, in C and in C++, the following are equivalent:
const char s[] = "Hello from Stack Overflow";
const char s[] = {'H','e','l','l','o',' ','f','r','o','m',' ','S','t','a','c','k',' ','O','v','e','r','f','l','o','w','\0'};
Because the string "Hello from Stack Overflow" has length 25, these produce a 26-element char array, as if the following had been written:
const char s[26] = "Hello from Stack Overflow";
const char s[26] = {'H','e','l','l','o',' ','f','r','o','m',' ','S','t','a','c','k',' ','O','v','e','r','f','l','o','w','\0'};
In C only, a program can exclude the terminating null character, such as if the string's length is known out of band. (Look for "including the terminating null character if there is room" in chapter 6.7.9 of the C99 standard.)
const char s[25] = "Hello from Stack Overflow";
const char s[25] = {'H','e','l','l','o',' ','f','r','o','m',' ','S','t','a','c','k',' ','O','v','e','r','f','l','o','w'};
But in C++, only the second is valid. If I know I will be manipulating the data with functions in the std::strn family, not the std::str family, is there a counterpart in the C++ language to the shorthand syntax of C?
My motivation differs from that of the other question about unterminated char arrays in C++. What motivates this is that several names of items in a game are stored in a two-dimensional char array. For example:
const char item_names[][16] = {
// most items omitted for brevity
"steel hammer",
{'p','a','l','l','a','d','i','u','m',' ','h','a','m','m','e','r'}
};
If there is no shorthand to declare an unterminated char array, then maximum-length names will have to be written character-by-character, which makes them less readable and less maintainable than to shorter names.
It is possible but I would agree with Alan Stokes' "Why"
For example using C++: Can a macro expand "abc" into 'a', 'b', 'c'?
It could be tweaked father to allow operate on any provided array and constrain it by length 16.
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp>
template <unsigned int N>
constexpr char get_ch (char const (&s) [N], unsigned int i)
{
return i >= N ? '\0' : s[i];
}
#define STRING_TO_CHARS_EXTRACT(z, n, data) \
BOOST_PP_COMMA_IF(n) get_ch(data, n)
#define STRING_TO_CHARS(STRLEN, STR) \
BOOST_PP_REPEAT(STRLEN, STRING_TO_CHARS_EXTRACT, STR)
const char item_names[][16] = { // most items omitted for brevity
"steel hammer",
STRING_TO_CHARS(16, "palladium hammer"),
//{'p','a','l','l','a','d','i','u','m',' ','h','a','m','m','e','r'},
};
but it could cost you more trouble in a long run...
the disadvantage of c-style array is that it can not be passed to or returned from functions (pass or return char* can give you an array of char* but not array of char[] in the end), we can use std::array to get around this
the advantage of c-style array is that small string literal can be used to initialize larger char[] in a char[][]'s initialize list (as in your example), for std::array we use std::max to simulate this
#include<array>
#include<utility>
#include<algorithm>
#include<iostream>
template<size_t string_length, typename T, T... ints, size_t string_literal_size>
constexpr std::array<char, string_length> generate_string_impl(std::integer_sequence<T, ints...> int_seq, char const(&s)[string_literal_size])
{
return { {s[ints]...} };
}
template<size_t string_length, size_t string_literal_size>
constexpr std::array<char, string_length> generate_string(char const(&s)[string_literal_size])
{
return generate_string_impl<string_length>(std::make_index_sequence<string_literal_size - 1>{}, s);
}
template<size_t ...string_literals_size>
constexpr std::array < std::array<char, std::max({ string_literals_size... }) - 1 > , sizeof...(string_literals_size) > generate_array_of_strings(char const(&...s)[string_literals_size])
{
return { generate_string < std::max({ string_literals_size... }) - 1 > (s)... };
}
int main()
{
constexpr auto array_of_string1 = generate_array_of_strings("1234", "12345", "123456");
//std::array<std::array<char,6>,3>{{
// {{ '1', '2', '3', '4', '\0', '\0' }},
// {{ '1', '2', '3', '4', '5', '\0' }},
// {{ '1', '2', '3', '4', '5', '6' }}
//}}
//std::array<std::array<char,6>,3> satisfies StandardLayoutType requirement
char const(&array_of_string2)[std::size(array_of_string1)][6] = reinterpret_cast<char const(&)[std::size(array_of_string1)][6]>(array_of_string1);
char const(*p_array_of_string2)[std::size(array_of_string1)][6] = reinterpret_cast<char const(*)[std::size(array_of_string1)][6]>(&array_of_string1);
for (int i = 0; i != 3; ++i)
{
for (int j = 0; j != 6; ++j)
{
std::cout << i << "," << j << " " << array_of_string2[i][j] << " " << (*p_array_of_string2)[i][j] << std::endl;
}
}
}
Related
What's the difference between the two? I know the difference between char* (char pointer) and char[] (char array). But I'm not sure the difference between char* [3] and char (*)[3]. I would think both name a pointer to a char array with 3 elements, but C++ makes some destinction between the two. I haven't found any useful information about the two declarations on the internet.
Difference between char* [number] and char (*)[number] in type declaration
char* [number] is an array of pointers to char.
char (*)[number] is a pointer to an array of char.
Some bonus examples:
char* (*)[number] is a pointer to an array of pointers to char.
char* (*)() is a pointer to a function that returns a pointer to char.
char* (*[number])() is an array of pointers to functions that return a pointer to char.
This
char* [3]
is array type that has 3 elements of the type char *.
This
char (*)[3]
is pointer type that points to array of the type char [3].
Here is a demonstrative program. In this program instead of the type char *[3] I will use the type const char *[3] because in C++ string literals (that are used in the program as initializers) have types of constant character arrays.
#include <iostream>
int main()
{
const size_t N = 3;
const char * a[N] = { "Hello", "everybody", "here" };
char s[N] = { '1', '2', '3' };
char ( *p )[N] = &s;
for ( size_t i = 0; i < N; i++ )
{
std::cout << a[i] << ' ';
}
std::cout << '\n';
for ( size_t i = 0; i < N; i++ )
{
std::cout << ( *p )[i] << ' ';
}
std::cout << '\n';
return 0;
}
The program output is
Hello everybody here
1 2 3
In the program there is used an array of the type const char *[3]
const char * a[N] = { "Hello", "everybody", "here" };
and a pointer of the type char ( * )[3] that is initialized by the address of an array of the type char[3]
char s[N] = { '1', '2', '3' };
char ( *p )[N] = &s;
void main() {
char str1[4] = { 'A','B','C','D' };
char str2[3] = { 'A','B','D' };
cout << strlen(str2)
}
the results is 31, and I don't know why it happens
You need nul-terminators on your C-style strings.
#include <iostream>
#include <cstring>
int main() {
char str1[4+1] = { 'A','B','C','D', '\0' }; // same as = "ABCD"
char str2[3+1] = { 'A','B','D', '\0' }; // same as = "ABD"
std::cout << std::strlen(str2) << '\n';
}
C strings (as in arrays of chars) by standard are arrays which terminating character is '\0'.
When you assign a string like this:
char* a = "hello";
it's equivalent to:
char a[6] = {'h', 'e', 'l', 'l', 'o', '\0'};
This kind of string works with strlen and similar (strcpy, strthis, strthat).
In C++ you should rather use the type String that you get including string. It's a class and you can use the functions of that class
#include <string>
...
std::string a = "hello";
int size = a.size();
When you do strlen of an array (actually the address for the first character), the strlen function iterates in your memory until it finds a \0, even if it goes out of your array and into whatever other data is in your memory.
The 31 you got means your strlen was going on for 31 times the size of a char in your memory before it finally met a \0 byte.
void reverse(char[] x) {
char* pStart = x;
char* pEnd = pStart + sizeof(x) - 2;
while(pStart < pEnd) {
char temp = *pStart;
*pStart = *pEnd;
*pEnd = temp;
pStart++;
pEnd--;
}
}
int main() {
char text[] = ['h','e','l','l','o'];
reverse(text);
cout << text << endl;
return 0;
}
I am new to C++ and stack overflow.
I am trying to reverse a string using pointers... I don't quite understand what I did wrong. Please help me out.
Additional question: What is the difference between a string and an array of characters?
sizeof(x) with x being a parameter of type char[] of a function does not give you the number of characters in the string but the size of a char*, probably 8 on a 64 bit system. You need to pass a C-String and use strlen(x) instead. Write char text[] = {'h','e','l','l','o','\0'} or char text[] = "hello" in main.
Note that sizeof() needs to be evaluatable at compile time; this is not possible on arrays with undetermined size like char[]-typed function arguments. When using sizeof on a variables like your char text[] = {'h','e','l','l','o'}, however, sizeof(text) will result in the actual size of the array.
char x[] is the same as char* x and the sizeof(x) is therefore the size of a pointer. So, because you cannot calculate the size of an array outside of the block it is declared in, I would eliminate that part from your function.
It would be much easier to provide the function with pointers to the first and last characters to be replaced:
void reverse(char* pStart, char* pEnd)
{
while (pStart < pEnd)
{
char temp = *pStart;
*pStart = *pEnd;
*pEnd = temp;
pStart++;
pEnd--;
}
}
So now it is quite easy to call this function - take the address (using ampersand &) of the the relevant characters in the array: &text[0] and &text[4].
To display an array of characters, there is a rule, that such "strings" HAVE to have after the last character a NULL character. A NULL character can be written as 0 or '\0'. That is why it has to be added to the array here.
int main()
{
// char text[] = "hello"; // Same like below, also adds 0 at end BUT !!!in read-only memory!!
char text[] = { 'h', 'e', 'l', 'l', 'o', '\0' };
reverse(&text[0], &text[4]);
std::cout << text << std::endl;
return 0;
}
why this code gives the wrong output?? Output is 5 and 9, shouldn't it be 5 and 4.
Here is the code
int main
{
char a[10] ={'a','b','c','d','e'};
char c[] = {'q','t','y','t'};
cout<<strlen(c)<<endl<<strlen(a);
return 0;
}
You have undefined behaviour, because you're calling strlen with a pointer to a character array that is not null-terminated (c). You need to pass null-terminated strings for this to work. This is an example, fixing that and some other errors, and including the required headers:
#include <iostream> // std:cout, std::endl
#include <cstring> // std::strlen
int main()
{
char a[10] ={'a','b','c','d','e'}; // OK, all remaining elements
// initialized to '\0'.
// Alternative: char a[10] = "abcde"
char c[] = {'q','t','y','t', '\0'}; // or char c[] = "qtyt";
std::cout << std::strlen(c) << std::endl;
std::cout << std::strlen(a) << std::endl;
}
c needs a null character at the end for strlen to work.
You can use
char c[N] = {'q','t','y','t'};
where N is 5 or greater.
or
char c[] = {'q','t','y','t', '\0'};
or
char c[] = "qtyt";
to add a null character at the end of c.
I am relatively new to C++. Recent assignments have required that I convert a multitude of char buffers (from structures/sockets, etc.) to strings. I have been using variations on the following but they seem awkward. Is there a better way to do this kind of thing?
#include <iostream>
#include <string>
using std::string;
using std::cout;
using std::endl;
char* bufferToCString(char *buff, int buffSize, char *str)
{
memset(str, '\0', buffSize + 1);
return(strncpy(str, buff, buffSize));
}
string& bufferToString(char* buffer, int bufflen, string& str)
{
char temp[bufflen];
memset(temp, '\0', bufflen + 1);
strncpy(temp, buffer, bufflen);
return(str.assign(temp));
}
int main(int argc, char *argv[])
{
char buff[4] = {'a', 'b', 'c', 'd'};
char str[5];
string str2;
cout << bufferToCString(buff, sizeof(buff), str) << endl;
cout << bufferToString(buff, sizeof(buff), str2) << endl;
}
Given your input strings are not null terminated, you shouldn't use str... functions. You also can't use the popularly used std::string constructors. However, you can use this constructor:
std::string str(buffer, buflen): it takes a char* and a length. (actually const char* and length)
I would avoid the C string version. This would give:
std::string bufferToString(char* buffer, int bufflen)
{
std::string ret(buffer, bufflen);
return ret;
}
If you really must use the C-string version, either drop a 0 at the bufflen position (if you can) or create a buffer of bufflen+1, then memcpy the buffer into it, and drop a 0 at the end (bufflen position).
If the data buffer may have null ('\0') characters in it, you don't want to use the null-terminated operations.
You can either use the constructor that takes char*, length.
char buff[4] = {'a', 'b', 'c', 'd'};
cout << std::string(&buff[0], 4);
Or you can use the constructor that takes a range:
cout << std::string(&buff[0], &buff[4]); // end is last plus one
Do NOT use the std::string(buff) constructor with the buff[] array above, because it is not null-terminated.
std::string to const char*:
my_str.c_str();
char* to std::string:
string my_str1 ("test");
char test[] = "test";
string my_str2 (test);
or even
string my_str3 = "test";
The method needs to know the size of the string. You have to either:
in case of char* pass the length to
method
in case of char* pointing to null
terminating array of characters you can
use everything up to null
character
for char[] you can use templates to
figure out the size of the char[]
1) example - for cases where you're passing the bufflen:
std::string bufferToString(char* buffer, int bufflen)
{
return std::string(buffer, bufflen);
}
2) example - for cases where buffer is points to null terminated array of characters:
std::string bufferToString(char* buffer)
{
return std::string(buffer);
}
3) example - for cases where you pass char[]:
template <typename T, size_t N>
std::string tostr(T (&array)[N])
{
return std::string(array, N);
}
Usage:
char tstr[] = "Test String";
std::string res = tostr(tstr);
std::cout << res << std::endl;
For the first 2 cases you don't actually have to create new method:
std::string(buffer, bufflen);
std::string(buffer);
std::string buf2str(const char* buffer)
{
return std::string(buffer);
}
Or just
std::string mystring(buffer);
Use string constructor that takes the size:
string ( const char * s, size_t n );
Content is initialized to a copy of the string formed by the first n
characters in the array of characters
pointed by s.
cout << std::string(buff, sizeof(buff)) << endl;
http://www.cplusplus.com/reference/string/string/string/
Non-null-terminated buffer to C string:
memcpy(str, buff, buffSize);
str[bufSize] = 0; // not buffSize+1, because C indexes are 0-based.
string value (reinterpret_cast(buffer), length);