views:

200

answers:

5

Hello, I have a struct like this

typedef struct bookStruct
{
   char title[80];
   char author[80];
} BookType;

And I have two strings like this

char *title = "A Book on C";
char *author = "A. Kelly";

Now I can't create a BookType like this

BookType book = {title, author};

Can anyone tell me what is wrong? How can I do that?

+2  A: 

You must use strcpy (if you know the length of the input) or a safe function instead.

A lot of the other answers made the same mistake of leaving un-terminated strings, a major source of security vulnerabilities.

The correct way is to use a safe string copy function, like StringCbCopy or roll your own (albeit not as robust):

// Copy at most n-1 characters to dst, truncating if strlen(src) > n-1
// and guaranteeing NUL-termination.
void safe_strcpy(char *dst, const char *src, size_t n) {
  strncpy(dst, src, n-1);
  dst[n-1] = 0;  // Guarantee NUL-termination.
}

Then you may use it as follows

void f(const char *title, const char *author) {
  BookType book;
  safe_strcpy(book.title, title, sizeof book.title);
  safe_strcpy(book.author, author, sizeof book.author);
}
Alex
+1  A: 

As far as I'm aware, there is no way of doing that in C. Your best bet is probably to use a macro:

#define TITLE "A Book On C"
#define AUTHOR "A. Kelley"

BookType book {TITLE, AUTHOR};

though this of course does not have exactly the same effect.

anon
+5  A: 

There are two possible solutions to your problem. The first of which is using the string literals in the place of construction:

BookType book = { "A book on C", "A. Kelly" };

In this case the compiler will copy the literals to the appropriate variables. If you cannot use the literals in the initialization, then you must copy the elements yourself:

BookType book = { 0 }; // 0 initalize
strncpy( book.title, title, sizeof(book.title)-1 );   
strncpy( book.author, author, sizeof(book.author)-1 );
David Rodríguez - dribeas
Wow, that is the ultimate example of pointless adherence to the the religious belief that strncpy is "safer" than strcpy. Or possibly it's a simple "think-o". Use `sizeof(book.title)-1` as the limit, or use strlcpy: your code does not in any sense "make sure that the size fits" :-)
Steve Jessop
You are right. The count should be `sizeof(book.title)-1`. On the other hand, the comment was not meant to mean that the code will make sure but that the user must make sure that it fits before calling the method.
David Rodríguez - dribeas
`MIN(sizeof(book.title)-1,strlen(title)))` is unnecessary. http://stackoverflow.com/questions/2658182/how-to-use-char-as-char/2658217#2658217
N 1.1
This doesn't guarantee null termination, either. ( when len(src) >= n )
Alex
@Alex: While the other commments are right, in your case the code does guarantee the null termination: the initailization `BookType book = { 0 }` initializes the whole structure to `0`. That includes `title[sizeof(title)-1]` and `author[sizeof(author)-1]`.
David Rodríguez - dribeas
Ah, right, I misunderstood the comment. Sorry, I thought it was describing the code, but it was an instruction to the programmer.
Steve Jessop
+3  A: 
void InitBookStruct(BookType *book, const char *title, const char *author){
   size_t title_length = sizeof book->title;
   size_t author_length = sizeof book->author;

   strncpy(book->title, title, title_length - 1); //-1, make way for null byte
   strncpy(book->author, author, author_length - 1);

   book->title[title_length - 1] = 0;
   book->author[author_length - 1] = 0;
}

Many ways to do, above is one of them.


From man pages,

char *strncpy(char *dest, const char *src, size_t n);

If the length of src is less than n, strncpy() pads the remainder of dest with null bytes.

So, specifying (one less than) the size of the dest is sufficient.

N 1.1
This doesn't guarantee null termination for either field.
Alex
@Alex: thanks. updated.
N 1.1
+2  A: 

If you change your structure to this it should work

typedef struct bookStruct
{
   char* title;
   char* author;
} BookType;
Ed
For C99 or C++.
JRL