5

I wanted to initialize a character array with the data from a character pointer. I wrote the following code for this:

(kindly excuse what I am doing with the structure and all .. actually this code is supposed to fit into something bigger and hence the strangeness of that structure and its use)

#include <iostream>
#include <string>

struct ABC 
{
    char a;
    char b;
    char c[16];
};

int main(int argc, char const *argv[])
{
    struct ABC** abc;
    std::string _r = "Ritwik";
    const char* r = _r.c_str();

    if (_r.length() <= sizeof((*abc)->c))
    {
        int padding = sizeof((*abc)->c) - _r.length();

        std::cout<<"Size of `c` variable is : "<<sizeof((*abc)->c)<<std::endl;
        std::cout<<"Value of padding is calculated to be : "<<padding<<std::endl;

        char segment_listing[ sizeof((*abc)->c)]; 

        std::cout<<"sizeof segment_listing is "<<sizeof(segment_listing)<<std::endl;

        memcpy(segment_listing, r, _r.length());
        memset( (segment_listing + _r.length()), ' ', padding);

        std::cout<<segment_listing<<std::endl;

    }
    return 0;
}

However, when I run my code I get these wierd characters at the end of my string:

(rh4dev01:~/rough) rghosh> ./crptr
Size of `c` variable is : 16
Value of padding is calculated to be : 10
sizeof segment_listing is 16
Ritwik          °×
(rh4dev01:~/rough) rghosh> ./crptr
Size of `c` variable is : 16
Value of padding is calculated to be : 10
sizeof segment_listing is 16
Ritwik           Ñ
(rh4dev01:~/rough) rghosh> ./crptr
Size of `c` variable is : 16
Value of padding is calculated to be : 10
sizeof segment_listing is 16
Ritwik          g
(rh4dev01:~/rough) rghosh> ./crptr
Size of `c` variable is : 16
Value of padding is calculated to be : 10
sizeof segment_listing is 16
Ritwik          pô
(rh4dev01:~/rough) rghosh> ./crptr
Size of `c` variable is : 16
Value of padding is calculated to be : 10
sizeof segment_listing is 16
Ritwik
(rh4dev01:~/rough) rghosh> ./crptr
Size of `c` variable is : 16
Value of padding is calculated to be : 10
sizeof segment_listing is 16
Ritwik          àå
(rh4dev01:~/rough) rghosh> ./crptr
Size of `c` variable is : 16
Value of padding is calculated to be : 10
sizeof segment_listing is 16
Ritwik           »
(rh4dev01:~/rough) rghosh> ./crptr
Size of `c` variable is : 16
Value of padding is calculated to be : 10
sizeof segment_listing is 16
Ritwik          pZ

Can you please explain why that is happening ? Since I am printing only a character array taht is only 16 characters in length, shouldn't only 16 characters get printed ? Where are those two (sometimes zero and sometimes one) characters coming from ?

More importantly, am I corrupting any memory (that does not belong to my character array c) by my padding ?

3
  • 2
    Assuming the use of std::cout I assume your question is meant to be C++ and not C (There is a difference). The correct way to use memcpy, memset or c-style arrays would be not at all. Besides what are you even trying to achieve? Commented May 30, 2013 at 17:36
  • @JohnDibling it is horrid because I am mixing c and c++ ? Commented May 30, 2013 at 17:41
  • 1
    Note that _r is a bad idea for a name because the standard reserves names beginning with underscores in the global namespace for the implementation. Commented May 30, 2013 at 17:59

4 Answers 4

2

Your string needs to be NUL terminated.

    memcpy(segment_listing, r, _r.length());
    memset( (segment_listing + _r.length()), ' ', padding-1);
    segment_listing[_r.length() + padding - 1] = '\0';

Perhaps you would be better served by using snprintf(), which will add the terminator for you:

    snprintf(segment_listing, sizeof(segment_listing), "%-*s",
             (int)sizeof(segment_listing)-1, r);
Sign up to request clarification or add additional context in comments.

7 Comments

And if you want the string to just be "Ritwik", without the spaces as padding, just do strncpy(segment_listing, r, _r.length());
thanks. But may i ask what changes when the array is not null terminated ? gcc knows that I declared only an array of 16 size. Should it not stop after printing 16 characters ? Also, can you please let me know if I am corrupting any memory or not (in the current implementation, not after your modification)
The NUL terminator is needed so that cout knows when to stop reading from the pointer passed to the output routine.
@user315052 I implemented your sugesstion but now there is a seg fault everytime. Here is teh gdb output: #0 0x0088b761 in __gnu_cxx::__exchange_and_add () from /usr/lib/libstdc++.so.6 (gdb) frame 1 #1 0x00871fe2 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string () from /usr/lib/libstdc++.so.6 (gdb) frame 2 #2 0x08048c63 in main (argc=1, argv=0xbfe86dd4) at crptr.cpp:35 35 return 0;
@user315052 thanks. Also. doing : memset( (segment_listing + _r.length()), ' ', padding); segment_listing[_r.length() + padding - 1] = '\0'; also fixes the issue. (segment_listing[16] would be out of bounds i guess. Must use only till segment_listing[15])
|
2

A C string is terminated by a 0 byte, which you havn't accounted for anywhere. You need to terminate your string with the value 0, and you'll have to take that extra byte in account in all your calculations.

Comments

2

There's no null character in segment_listing

Comments

-1
const int SIZE = 16;  //or 17 if you want 16 + null char
//pre-initialise array - then will automatically be null terminated
char segment_listing[SIZE] = {0};

8 Comments

You can mimic it with a memset() call. The danger is if you overwrite the last character of the buffer, you lose your terminator. It is safer to explicitly place it there.
you need constexpr, not const.
@RitwikG char a[16] = {0}; creates an array of 16 elements null initialised. it is like doing memset() but more elegant. Did you try it?
@BatchyX can you please clarify?
In C++, the size of an array must be what is called a constant expression, i.e. an expression known at compile time. constant expressions may contains literal constants, operators, constexpr constants and the result of applying constexpr functions to constant expressions. A const int variable can not be part of a constant expression, as it can be initialized to something which is not known at compile time (like, say, time()), so your code is invalid. In your case, you initialize it using a constant expression, so you can declare SIZE as a constexpr int instead, and it will be valid.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.