4

I have written a small program:

void showrecord()
{
     char *a[]={ "O_BILLABLE_ACCOUNT","O_CUSTOMER_TYPE_INDICATOR",
                 "O_A_PARTY_MSISDN_ID","O_A_PARTY_EQUIPMENT_NUMBER",
                 "O_A_PARTY_IMSI","O_A_PARTY_LOCATION_INFO_CELL_ID",
                 ...  
               };

     vector<std::string> fields(a,a+75);

     cout<<"done!!!"<<endl;
}

int main()
{
     showrecord();
}

I have array of string literals and i want them to be copied into a vector. I did not find any other easy way to do it :(.Or if there is any direct way to initialize the vector without using the array ,that would be very much helpful. This is dumping the core after i run the executable on unix. It gives me a warning though like :

Warning 829: "test.cpp", line 12 
# Implicit conversion of string literal to 'char *' is deprecated.
D_TYPE","O_VARCHAR_5","O_VARCHAR_6","O_VARCHAR_7","O_VARCHAR_8","O_VARCHAR_9"};

But the same code is running fine on windows without any problem. I am using the compiler aCC on HPUX.

Please help! EDIT below is teh stacktrace of the dump.

(gdb) where
#0  0x6800ad94 in strlen+0xc () from /usr/lib/libc.2
#1  0xabc0 in std::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string<char,std::char_traits<char>,std::allocator<char>>+0x20 ()
#2  0xae9c in std<char const **,std::basic_string<char,std::char_traits<char>,std::allocator<char>> *,std::allocator<std::basic_string<char,std::char_traits<char>,std::allocator<char>>>>::uninitialized_copy+0x60 ()
#3  0x9ccc in _C_init_aux__Q2_3std6vectorXTQ2_3std12basic_stringXTcTQ2_3std11char_traitsXTc_TQ2_3std9allocatorXTc__TQ2_3std9allocatorXTQ2_3std12basic_stringXTcTQ2_3std11char_traitsXTc_TQ2_3std9allocatorXTc____XTPPCc_FPPCcT118_RW_is_not_integer+0x2d8
    ()
#4  0x9624 in showrecord () at test.cpp:13
#5  0xdbd8 in main () at test.cpp:21
Vijay
  • 65,327
  • 90
  • 227
  • 319
  • what's this `uninitialized_copy` in the stack trace? Are you showing the compete program that causes the crash? Also, I would try this in gcc, if it works than you may have a problem with aCC (it's quite old, isn't it? HPUX is phasing out AFAIK) – davka Jun 14 '11 at 11:39
  • @davka: that is an implementation detail of the library, I have seen functions with that name in STL implementation to copy construct from a set of iterators into some uninitialized memory. – David Rodríguez - dribeas Jun 14 '11 at 12:00
  • @davka `uninitialized_copy` is probably being called by the constructor of `std::vector`. – James Kanze Jun 14 '11 at 12:02

3 Answers3

5

Why 75?

Change

vector<std::string> fields(a,a+75);

to

vector<std::string> fields(a, a + sizeof a / sizeof *a);

There's no arguably 'better' way to initialize your vector for C++03, but for C++0x you have access to a more convenient syntax, dispensing with the C array:

std::vector<std::string> fields {
    "O_BILLABLE_ACCOUNT",
    // ...
};
Luc Danton
  • 34,649
  • 6
  • 70
  • 114
  • I'd prefer `fields(&a[0], &a[sizeof(a)/sizeof(a[0])])` for readability. – Kijewski Jun 14 '11 at 11:26
  • Because the array contains 75 strings.and it is fixed.will never change – Vijay Jun 14 '11 at 11:28
  • @Rahul Have you tried applying my fix? The code you provided us runs without a hitch with it. This kind of hardcoded value is a maintenance timebomb and this one seems to have gone off before said maintenance. – Luc Danton Jun 14 '11 at 11:29
  • @Rahul: http://en.wikipedia.org/wiki/Magic_number_(programming)#Unnamed_numerical_constants – Kijewski Jun 14 '11 at 11:30
  • 3
    @Kay: I think `&a[sizeof(a)/sizeof(a[0])]` yields undefined behavior because you dereference an pointer to an invalid object. – Yakov Galka Jun 14 '11 at 11:39
  • @ybungalobill It's an explicit special case in both C and C++, it's equivalent to `a + sizeof a / sizeof *a` **and** is not considered dereferencing (unlike the normal case). – Luc Danton Jun 14 '11 at 11:44
  • 1
    @Kay Technically, that is undefined behavior, since it involves `a[onePastEnd]`, which is undefined behavior. (By definition, `a[onePastEnd]` is the same as `*(a + onePastEnd)`, which is a dereference.) – James Kanze Jun 14 '11 at 11:50
  • 2
    @Luc: Nope, it's only a special case in C99. In C++, [it is technically undefined behavior](http://stackoverflow.com/questions/3144904/). – fredoverflow Jun 14 '11 at 11:50
  • For compile-time constant array sizes you could/should use a template to deduce the array size as in mloskot's answer below, so you don't have to divide any sizes. – Kerrek SB Jun 14 '11 at 15:50
4

Try const char* a[] instead of char* a[]. String literals are of type const char*, not char*, and hence you get the warning.

Anteru
  • 19,042
  • 12
  • 77
  • 121
2

Here is possible solution which IMO is a little bit more general - uses reusable function that works with string arrays of any size:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>

template <typename Array, std::size_t Size>
std::vector<std::string> make_vector(Array (&ar)[Size])
{
    std::vector<std::string> v(ar, ar + Size);
    return v;
}

int main()
{
     char const* a[] = { "Aa","Bb", "Cc","Dd", "Ee","Ff" };

     // copy C-array to vector
     std::vector<std::string> fields = make_vector(a);

     // test
     std::copy(fields.begin(), fields.end(),
               std::ostream_iterator<std::string>(std::cout, "\n"));
}
mloskot
  • 37,086
  • 11
  • 109
  • 136
  • 1
    You can even remove the explicit `v`, just `return std::vector...`. Also, you could make a second version which takes an explicit size argument to accommodate arrays that aren't of compile-time constant size. – Kerrek SB Jun 14 '11 at 15:47
  • @Kerrek SB - yes, further templatization / improvements are possible or even advised. I left it as an exercice to the OP – mloskot Jun 14 '11 at 16:23