Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

how to copy strings into a linked list?

12 views
Skip to first unread message

Jim Showalter

unread,
Aug 23, 2006, 4:46:06 PM8/23/06
to
I'm trying to write code that gets fixed-length strings from the user
and then stores them in a linked list.

Here's the definition of my list node:

struct node {char str[19]; struct node* next; };

And here is my attempt at Push(), the function that adds new nodes
to the list:

void Push(struct node** head, char *str) {

struct node* newNode = malloc(sizeof(struct node));
newNode->str = *str;
newNode->next = *head;
*head = newNode;
}

It worked fine when testing with int's, but I don't know how to get the
strings copied to "newNode->str".

Walter Roberson

unread,
Aug 23, 2006, 4:54:47 PM8/23/06
to
In article <i83Hg.730$bM....@newsread4.news.pas.earthlink.net>,

Jim Showalter <jim_sh...@hotmail.com> wrote:
>I'm trying to write code that gets fixed-length strings from the user
>and then stores them in a linked list.

>Here's the definition of my list node:

>struct node {char str[19]; struct node* next; };

>And here is my attempt at Push(), the function that adds new nodes
>to the list:

>void Push(struct node** head, char *str) {

> struct node* newNode = malloc(sizeof(struct node));

You should check the result of the malloc() -- if there was no
available memory then malloc() will return a NULL pointer.

> newNode->str = *str;
> newNode->next = *head;
> *head = newNode;
>}

>It worked fine when testing with int's, but I don't know how to get the
>strings copied to "newNode->str".

strncpy( &newNode->str, str, sizeof(newNode->str) - 1 );
newNode->str[sizeof newNode->str - 1] = '\0';

But this code depends upon you really wanting strings -- which is
to say, null terminated character arrays. You said that you
have "fixed-length strings": does that mean that there are 18
used characters and the 19th is for the null, or does that mean
that there are 19 used characters and you will supply the null
when needed? The code as written assumes that the null needs
to be stored and protects itself in case the null was not present
in the first 18 characters of the input.
--
Programming is what happens while you're busy making other plans.

Jim Showalter

unread,
Aug 23, 2006, 5:55:10 PM8/23/06
to
Walter Roberson wrote:

> In article <i83Hg.730$bM....@newsread4.news.pas.earthlink.net>,
> Jim Showalter <jim_sh...@hotmail.com> wrote:

> You should check the result of the malloc() -- if there was no
> available memory then malloc() will return a NULL pointer.

Thanks - I will when I get this function working.

>
> strncpy( &newNode->str, str, sizeof(newNode->str) - 1 );
> newNode->str[sizeof newNode->str - 1] = '\0';

I think you're close, but now I'm getting:
"warning: passing argument 1 of ‘strncpy’ from incompatible pointer type"

>
> .... does that mean that there are 18
> used characters and the 19th is for the null, ...

Yes

Walter Roberson

unread,
Aug 23, 2006, 6:14:02 PM8/23/06
to
In article <294Hg.9709$Qf....@newsread2.news.pas.earthlink.net>,
Jim Showalter <jim_sh...@hotmail.com> wrote:
>Walter Roberson wrote:

>> .... does that mean that there are 18
>> used characters and the 19th is for the null, ...

>Yes

In that case, you can use strcpy() instead of strncpy(), and
you can skip the statement that sets the final character to '\0'.
However, it is -safer- to use strncpy() and set the '\0'
as that way a small mistake somewhere else in constructing the
string will not end up potentially trashing random bits of memory.

>> strncpy( &newNode->str, str, sizeof(newNode->str) - 1 );

>I think you're close, but now I'm getting:


>"warning: passing argument 1 of ‘strncpy’ from incompatible pointer type"

Ugly, why doesn't the warning message just stick to the basic
character set instead of moving into UTF-8 extensions for whatever
kind of quotation marks it is using around strncpy ?

Anyhow, better than &newNode->str would be either
newnode->str without the &, or else &newNode->str[0]

pete

unread,
Aug 23, 2006, 9:32:53 PM8/23/06
to
Jim Showalter wrote:
>
> I'm trying to write code that gets fixed-length strings from the user
> and then stores them in a linked list.

In line_to_string.c, string_node is the function
which copies strings into a linked list.

/* BEGIN line_to_string.c */

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>

struct list_node {
struct list_node *next;
void *data;
};

int line_to_string(FILE *fp, char **line, size_t *size);
void list_free(struct list_node *node, void (*free_data)(void *));
void list_fprint(FILE *stream, struct list_node *node);
struct list_node *string_node(struct list_node **head,
struct list_node *tail,
char *data);

int main(void)
{
struct list_node *head, *tail;
int rc;
char *buff_ptr;
size_t buff_size;
long unsigned line_count;

puts(
"\nThis program makes and prints a list of all the lines\n"
"of text entered from the standard input stream.\n"
"Just hit the Enter key to end,\n"
"or enter any line of characters to continue."
);
tail = head = NULL;
line_count = 0;
buff_size = 0;
buff_ptr = NULL;
while ((rc = line_to_string(stdin, &buff_ptr, &buff_size)) > 1) {
++line_count;
tail = string_node(&head, tail, buff_ptr);
if (tail == NULL) {
break;
}
puts(
"\nJust hit the Enter key to end,\n"
"or enter any other line of characters to continue."
);
}
switch (rc) {
case EOF:
if (buff_ptr != NULL && strlen(buff_ptr) > 0) {
puts("rc equals EOF\nThe string in buff_ptr is:");
puts(buff_ptr);
++line_count;
tail = string_node(&head, tail, buff_ptr);
}
break;
case 0:
puts("realloc returned a null pointer value");
if (buff_size > 1) {
puts("rc equals 0\nThe string in buff_ptr is:");
puts(buff_ptr);
++line_count;
tail = string_node(&head, tail, buff_ptr);
}
break;
default:
break;
}
if (line_count != 0 && tail == NULL) {
puts("Node allocation failed.");
puts("The last line entered didnt't make it onto the list:");
puts(buff_ptr);
}
free(buff_ptr);
puts("\nThe line buffer has been freed.\n");
printf("%lu lines of text were entered.\n", line_count);
puts("They are:\n");
list_fprint(stdout, head);
list_free(head, free);
puts("\nThe list has been freed.\n");
return 0;
}

int line_to_string(FILE *fp, char **line, size_t *size)
{
int rc;
void *p;
size_t count;

count = 0;
while ((rc = getc(fp)) != EOF) {
++count;
if (count + 2 > *size) {
p = realloc(*line, count + 2);
if (p == NULL) {
if (*size > count) {
(*line)[count] = '\0';
(*line)[count - 1] = (char)rc;
} else {
ungetc(rc, fp);
}
count = 0;
break;
}
*line = p;
*size = count + 2;
}
if (rc == '\n') {
(*line)[count - 1] = '\0';
break;
}
(*line)[count - 1] = (char)rc;
}
if (rc != EOF) {
rc = count > INT_MAX ? INT_MAX : count;
} else {
if (*size > count) {
(*line)[count] = '\0';
}
}
return rc;
}

void list_free(struct list_node *node, void (*free_data)(void *))
{
struct list_node *next_node;

while (node != NULL) {
next_node = node -> next;
free_data(node -> data);
free(node);
node = next_node;
}
}

void list_fprint(FILE *stream, struct list_node *node)
{
while (node != NULL) {
fputs(node -> data, stream);
putc('\n', stream);
node = node -> next;
}
}

struct list_node *string_node(struct list_node **head,
struct list_node *tail,
char *data)
{
struct list_node *node;

node = malloc(sizeof *node);
if (node != NULL) {
node -> next = NULL;
node -> data = malloc(strlen(data) + 1);
if (node -> data != NULL) {
if (*head == NULL) {
*head = node;
} else {
tail -> next = node;
}
strcpy(node -> data, data);
} else {
free(node);
node = NULL;
}
}
return node;
}

/* END line_to_string.c */


--
pete

Jim Showalter

unread,
Aug 23, 2006, 10:33:34 PM8/23/06
to
Walter Roberson wrote:

> In article <294Hg.9709$Qf....@newsread2.news.pas.earthlink.net>,
> Jim Showalter <jim_sh...@hotmail.com> wrote:
>>Walter Roberson wrote:
>
> In that case, you can use strcpy() instead of strncpy(), and
> you can skip the statement that sets the final character to '\0'.
> However, it is -safer- to use strncpy() and set the '\0'
> as that way a small mistake somewhere else in constructing the
> string will not end up potentially trashing random bits of memory.

Thanks for the tip. I may stick with strncpy() as you suggest.

>
> Anyhow, better than &newNode->str would be either
> newnode->str without the &, or else &newNode->str[0]

newnode->str works. Thank you!

Jim Showalter

unread,
Aug 23, 2006, 10:52:46 PM8/23/06
to
pete wrote:
>
> In line_to_string.c, string_node is the function
> which copies strings into a linked list.
>
> /* BEGIN line_to_string.c */
>

Wow - thanks for the routines! And it all compiled without a whimper. That
should get me over this particular hurdle.

>
> /* END line_to_string.c */
>

Thanks again, pete!

0 new messages