Reputation: 370
I'm very new in C programming and I need to create a phone book. Each entry must have a name, a phone number and a notes section. The thing is that the size of notes section should be changeable according to input. For example, if the user enters a string with 30 characters, size of note should be 30. I couldn't figure out how to do it.
Here is my code so far:
#include <stdio.h>
#include <stdlib.h>
#include <note>
struct Entries {
char name[50];
char phoneNumber[11];
char * note;
note = (char *)malloc(5*sizeof(char));
}Entries;
int main()
{
int command;
int counter = 0;
char tempNote[50];
char tempName[50];
char tempPhoneNumber[11];
while(1){
printf("Welcome to myPhoneBook! Please select an option:\n 1) New entry\n 2) List all entries\n 3) Edit\n 4) Delete\n 5) Search\n");
scanf("%d", &command);
if(command == 1){
struct Entries entry;
printf( "Enter a name:\n");
scanf("%s",tempName);
strcpy(entry.name, tempName);
printf( "Enter a phone:\n");
scanf("%s",tempPhoneNumber);
strcpy(entry.phoneNumber, tempPhoneNumber);
printf( "Enter a note:\n");
scanf("%s",tempNote);
entry.note = (char *)realloc(entry.note,strlen(tempNote));
strcpy(entry.note, tempNote);
counter++;
}
}
return 0;
}
When the user enters name, phoneNumber and note for the first time, the program automatically stops working despite the fact that it should've asked to user the attributes forever.
Upvotes: 0
Views: 1750
Reputation: 4444
Close,
If the user enters a string with 30 characters, size of note should be 30.
Strings in C are null-terminated, thus you need to reserve space for the terminal character ('\0'). You could alternately store the string as both the length of the string and the characters, but then you would need to decide the maximum number of characters expressible.
The easiest is to use strdup() to allocate just enough space for the string and the null terminator.
if( entry.note ) free(entry.note); //avoid leaking memory
entry.note = strdup(tempNote);
Or you could use a struct containing length and data, allocating, assigning, and freeing using the following,
typedef struct {
unsigned short int len;
char str[1];
} strwlen_t;
strwlen_t* string_withlen_alloc(unsigned short int size) {
strwlen_t* p = malloc( size + sizeof(strwlen_t) );
p->str[0] = '\0';
p->len = 0;
return p;
}
strwlen_t* strwlen_dup(char* str) {
unsigned short int len = strlen(str);
strwlen_t* p = malloc( len + sizeof(strwlen_t) );
memcpy(p->str,str);
p->len = len;
return p;
}
void strwlen_free(strwlen_t* p) {
free(p);
}
strwlen_t* strwlen_cpy(strwlen_t* dp,char* sp) {
strcpy(dp->str,sp);
dp->len = len(sp);
return(dp);
}
Declare your Entries struct,
struct Entries {
char name[50];
char phoneNumber[11];
strwlen_t* note;
} Entries;
Then you could use,
if( entry.note ) free(entry.note);
entry.note = strwlen_dup(tempNote);
And print entry.note using,
printf("note: %s\n",entry.note.str);
Upvotes: 0
Reputation: 1681
I would suggest learning the basics of C first. C is really just a portable assembler with macros. You absolutely need to know how pointers and memory allocation work before you can get anything done :)
Btw., congratulations for beginning to learn C, this will give you a lot of great insights about the nature of both computers and programming languages :):)
Upvotes: 0
Reputation: 10184
Replace
entry.note = (char *)realloc(entry.note,strlen(tempNote));
with
entry.note = malloc(strlen(tempNote) + 1);
Also
Remove
note = (char *)malloc(5*sizeof(char)
from the struct
definition. It doesn't belong there.
Upvotes: 0
Reputation: 134286
You can make use of a flexible array member. That's much better approach.
Quoting from the C11
standard, chapter §6.7.2.1
[...] the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member. In most situations, the flexible array member is ignored. In particular, the size of the structure is as if the flexible array member were omitted except that it may have more trailing padding than the omission would imply. However, when a
.
(or->
) operator has a left operand that is (a pointer to) a structure with a flexible array member and the right operand names that member, it behaves as if that member were replaced with the longest array (with the same element type) that would not make the structure larger than the object being accessed; the offset of the array shall remain that of the flexible array member, even if this would differ from that of the replacement array. If this array would have no elements, it behaves as if it had one element but the behavior is undefined if any attempt is made to access that element or to generate a pointer one past it.
and the example
EXAMPLE 2 After the declaration:
struct s { int n; double d[]; };
the structure
struct s
has a flexible array memberd
. A typical way to use this is:int m = /* some value */; struct s *p = malloc(sizeof (struct s) + sizeof (double [m]));
and assuming that the call to
malloc
succeeds, the object pointed to byp
behaves, for most purposes, as ifp
had been declared as:struct { int n; double d[m]; } *p;
Now, following the above, you can scan an input, use the input length as m
and then , allocate enough memory to hold the input.
Upvotes: 2