4

I am creating a struct called student. In order to store the name, is there anything wrong with just declaring a char pointer in the struct instead of a char array with a predefined size? I can then assign a string literal to the char pointer in the main code.

struct student
{
    int ID;
    char* name;
};
3
  • 11
    use std::string Commented Apr 22, 2015 at 9:23
  • The problem with making a pointer point to a string literal, is that you cant modify the string but you loose that since you only have a char* and not a const char*, and if you dynamically allocate memory for it then it's not to hard to get memory leaks. The problem with a fixed-size array is that you can't enlarge it if you want a bigger string, and if you have a very small string you have a lot of wasted space. In C++ the correct solution is std::string, in C the solution depends on your use-cases. Commented Apr 22, 2015 at 9:26
  • I can't modify what name is pointing to but can't I just point name to a new string literal anytime I want to change the name? Commented Apr 22, 2015 at 9:38

6 Answers 6

6

It really depends on your use case. As suggested above you should use std::string in C++. But if you are using C-style strings, then it depends on your usage.

Using char[] of defined size you can avoid errors due to null pointers and other pointer related errors like memory leaks, dangling pointers etc., but you might not be making an optimal use of memory. You may 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 names of student will be different and in many cases much less than MAX_SIZE. As such much memory will be wasted here. Or in some cases it might be greater than MAX_SIZE. You may have to truncate the names here to avoid memory corruption.

In other case where we define use char*, memory is not wasted as we allocate only the required amount, but we must take care of memory allocation and freeing.

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

Then while storing 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 are again allocating memory to name, you should free previously allocated memory to avoid memory leaks. Also another thing to consider is NULL checks for pointers before use, i.e., you should always check as

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

Although you can create macros to do this, but these are basic overheads with pointers.

Another advantage of using pointers is that if there are many similar names then you can point multiple pointers to same name and save memory, but in array you will be having separate memory for all, e.g,

// 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 this might not be your case, but just saying that pointers may help avoid extra usage.

Hope it will help you :)

Sign up to request clarification or add additional context in comments.

1 Comment

This is a very useful answer. Plus one. I agree, depends on use. If your input is large (ie millions of lines of text greater than 20 or so characters), using std::string is going to put millions of allocations on the heap and then you have to be very careful that you aren't copying them anywhere. In that case it MIGHT be worth looking into using a char[] or at least only using the std::string one time and then using std:string_view in your code.
5

Don't use either, use std::string. I (and many others) guarantee that compared to either char* or char[]:

  1. it will be easier to use and
  2. it will be less prone to bugs.

Comments

4

Difference is same as difference between static and dynamic memory allocation. With former ( static ) you have to specify size enough to store the name whereas with latter you have to pay attention to delete it when in no need.

Although it's all time better to use std::string.

Comments

2

Unless there is a strong reason to not do so, I'd suggest you to use a convenient string class like std::string, instead of a raw char* pointer.

Using std::string will simplify your code a lot, e.g. the structure will be automatically copyable, the strings will be automatically released, etc.

A reason why you could not use std::string is because you are designing an interface boundary, think of e.g. Win32 APIs which are mainly C-interface-based (implementation can be in C++), so you can't use C++ at the boundary and instead must use pure C.
But if that's not the case, do yourself a favor and use std::string.

Note also that in case you must use a raw char* pointer, you have several design questions to clarify, e.g.:

  1. Is this an owning pointer, or an observing pointer?

  2. If it's an owning pointer, in what way is it allocated, and in what way is it released? (e.g. malloc()/free(), new[]/delete[], some other allocator like COM CoTaskMemAlloc(), SysAllocString(), etc.)

  3. If it's an observing pointer, you must make sure that the observed string's lifetime exceeds that of the observing pointer, to avoid dangling references.

All these questions are just non-existent if you use a convenient string class (like e.g. std::string).

Note also that, as some Win32 data structures do, you can have a maximum-sized string buffer inside your structure, e.g.

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

In this case you could use C functions like strcpy(), or safer variants, to deep-copy a source string into the Name buffer. In that case you have good locality since the name string is inside the structure, and a simplified memory management with respect to the raw char* pointer case, but at the cost of having a pre-allocated memory buffer.
This may or may not be a better option for you, depending on your particular programming context. Anyway, keep in mind that this is a more C-like approach; a better C++ approach would be to just use a string class like std::string.

Comments

1

TL;DR - use std::string, as we're talking in c++.


EDIT: Previously, as per the C tag (currently removed)

As per your requirement, assigning a string literal needs a pointer, you cannot do that with an array, anyway.#

If you're using that pointer to store the base address of a string literal, then it is ok. Otherwise, you need to

  • allocate memory before using that pointer
  • deallocate memory once you're done with it.

#) Base address of compile time allocted array cannot be changed, thus assignment won't work.

Comments

0

Use the std::string library. It is more easier to work with. And has way more functionality compared to the built in counterparts.

Comments

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.