Reputation: 11
Im making a really simple TODOlist in C.
My add function takes a char *
as its parameter. When I add it to my char **
list of reminders, it adds the memory address of my buffer instead of the value of the string.
The problem becomes apparent when I run the given source below.
If you try to [a]dd a string, say "Test", and then issue command [p]rint, a "p" will be printed.
I understand that this is because my list[0]
is holding a pointer to my buffer, so that when the value of buffer changes, so does the value in my list.
My C is rusty and I know that strcpy()
might solve this issue? But is this the usual way to handle this?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int size = 0;
int capacity = 50;
char **list;
void initList() {
list = malloc( capacity * sizeof( char * ) );
for (int i = 0; i < capacity; i++ ) {
list[i] = malloc( 256 * sizeof( char ) );
}
}
void saveReminders() {
}
void add( char *reminder ) {
list[size++] = reminder;
}
void delete( int index ) {
}
void print() {
for ( int i = 0; i < size; i++ )
printf( "%s\n", list[i] );
}
void quit() {
saveReminders();
exit( 0 );
}
void readReminders() {
}
void helpMenu() {
printf( "Enter a command:\n" );
printf( "[a]dd a reminder\n" );
printf( "[d]elete a reminder\n" );
printf( "[p]rint all reminders\n" );
printf( "[q]uit\n" );
}
void menu() {
helpMenu();
while ( 1 ) {
char buffer[64];
int index = 0;
printf( "> " );
scanf( "%s", buffer );
if ( strcmp( buffer, "a" ) == 0 ) {
printf( "Enter a reminder:\n> " );
scanf( "%s", buffer );
add( buffer );
helpMenu();
}else if ( strcmp( buffer, "d" ) == 0 ) {
printf("Remove which index?\n> " );
scanf( "%d", &index );
delete( index );
helpMenu();
}else if ( strcmp( buffer, "p" ) == 0 ) {
print();
helpMenu();
}else if ( strcmp( buffer, "q" ) == 0 ) {
quit();
}
}
}
int main( int argc, char* argv[] ) {
initList();
menu();
}
Upvotes: 1
Views: 77
Reputation: 1198
instead of:
list[size++] = reminder
use
strcpy(list[size++], reminder)
or better yet, when you scanf, remember the number of characters written, pass it to add(), then do:
strncpy(list[size++], reminder, len)
Upvotes: 0
Reputation: 134366
Yes, you thought it right. In your code, instead of assigning the pointer itself, do something like
strcpy(list[size++], reminder);
to copy the content. See the man page for reference.
If you'd like to have a second approach, you don't need to malloc()
for each and every list[i]
either. Instead of using malloc()
and then strcpy()
, you can directly use strdup()
and assign the return value to each list[i]
to get the same result.
That said, some other points to note
list[size++]
, ensure that size
is less than capacity
, otherwise you'll end up overrunning the allocated memory, creating undefined behavior.scanf( "%s", buffer );
should be scanf( "%63s", buffer );
to prevent any possible buffer overflow.malloc()
for success before using the returned pointer.sizeof( char )
is defined to be 1
in C standard. using it as a multiplier is redundant.Upvotes: 3