Using char * or char [] in a C ++ structure

I create struct

called student

. To preserve the name, is there something wrong with just declaring a pointer char

in struct

instead of char

a predefined size array ? Then I can assign the string literal to the pointer char

in the main code.

struct student
{
    int ID;
    char* name;
};

      

+3


source to share


6 answers


Don't use either, use std::string

. I (and many others) guarantee that compared to char*

or char[]

:



  • it will be easier to use and
  • it will be less error prone.
+7


source


The difference is the same as the difference between static and dynamic memory allocation. With the former (static), you must specify a size large enough to hold the name, whereas with the latter, you must pay attention to remove it when not needed.



Although it is better to use all the time std::string

.

+5


source


TL; DR - use std::string

as we speak in c++

.


EDIT: previously, as per tag C

(currently removed)

As per your requirement, you need a pointer to assign a string literal, you cannot do it with an array. #

If you use this pointer to store the base address of a string literal, then that's okay. Otherwise, you need

  • allocate memory before using this pointer
  • free up memory as soon as you're done with it.

#) The base address of a compile-time array cannot be changed, so assignment

will not work.

+3


source


Unless there is a good reason not to do this, I suggest you use a convenient string class , for example , instead of raw . std::string

char*

Using std::string

will simplify your code eg. the structure will be automatically copied, the lines will be automatically released, etc.

The reason you couldn't use std::string

is because you are designing an interface border, think for example. Win32 APIs which are mostly based on the C interface (the implementation could be in C ++), so you cannot use C ++ on the boundary and must instead use pure C.
But if that is not the case, do yourself a favor and use std::string

...

Note also that if you must use a raw pointer char*

, you have a few design questions to clarify, for example:

  • Is it a possessor pointer or an observation pointer?

  • If it is an owning index, how is it allocated and how is it released? (e.g. malloc()

    / free()

    , new[]

    / delete[]

    , some other allocator like COM CoTaskMemAlloc()

    , SysAllocString()

    etc.)

  • If it is a watch pointer, you must ensure that the observed string has a lifetime longer than the watch pointer to avoid dangling references.

All of these questions are simply missing if you are using a convenient string class (for example std::string

).

Note also that, as some Win32 data structures do, you can have a maximum size string buffer inside your structure, for example

struct Student
{
    int ID;
    char Name[60];
};

      

In this case, you could use C functions like strcpy()

or safer options to deep copy the original string into the buffer Name

. In this case, you have good locality, since the name string is inside the structure and simplified memory management with respect to the char * source code, but at the cost of having a pre-allocated memory buffer.
This may or may not be the best option for you, depending on your specific programming context. Anyway, keep in mind that this is a more C-like approach; the best approach in C ++ would be to just use a string class eg std::string

.

+3


source


Use the std :: string library . It is easier to work with him. And it has more features compared to the built-in counterparts.

+1


source


It really depends on your use case. As suggested above, you should be using std::string

in C ++. But if you are using C style strings, it depends on your use.

By using char [] of a specific size, you can avoid errors due to null pointers and other pointer-related errors like memory leaks, dangling pointers, etc., but you may not be using optimal memory usage. You can for example define

#define MAX_SIZE 100
struct student
{
    int ID;
    char name[MAX_SIZE];
};

      

And then

#define STUDENT_COUNT 50
struct student many_students[STUDENT_COUNT];

      

But the length of student names will vary and in many cases are much less than MAX_SIZE. Because such memory will be wasted here. Or, in some cases, it may be greater than MAX_SIZE. You may need to truncate names to avoid memory corruption.

In the other case, when we define the use of char * , no memory is wasted since we only allocate the required amount, but we have to take care of allocating and freeing memory.

struct student
{
    int ID;
    char *name;
};

      

Then, when storing the name, we need to do something like this:

struct student many_student[STUDENT_COUNT];
int i;
for( i=0; i<STUDENT_COUNT; i++) {
    // some code to get student name
    many_student[i].name = (char*)malloc(name_length+1 * sizeof(char));
    // Now we can store name
}

// Later when name is no longer required free it
free(many_student[some_valid_index_to_free].name);
// also set it to NULL, to avoid dangling pointers
many_student[some_valid_index_to_free].name = NULL;

      

Also, if you re-assign memory for a name, you must free the previously allocated memory to avoid memory leaks. Another thing to consider is checking for NULL for pointers before using, i.e. You should always check how

if(many_students[valid_index].name!=NULL) {
    // do stuff
}

      

While you can create macros to do this, it's a major pointer overhead.

Another advantage of using pointers is that if there are many similar names, you can point multiple pointers to the same name and keep the memory, but in the array you will have separate memory for all, for example

// IF we have a predefined global name array
char *GLOBAL_NAMES[] = {"NAME_1", "NAME_2", "NAME_3", "NAME_4", ... , "NAME_N"};


// using pointers, just need to assign name to correct pointer in array
many_student[valid_index_1].name = GLOBAL_NAMES[INDEX_NAME_1];
many_student[valid_index_2].name = GLOBAL_NAMES[INDEX_NAME_1];

// In case of array we would have had to copy.

      

Although that might not be your business, just say pointers can help avoid additional use.

Hope this helps you :)

0


source







All Articles