So I have some code which is eventually going to create a linked list of sentences which contains words and the punctuation that ends the sentence but right now I'm having a very peculiar issue:
struct sentence {
char *words[10];
char punc;
struct sentence *next;
};
void split(char *buf, char *split[], size_t max) {
char * token = strtok(buf, " ");
int i = 0;
while (token != NULL) {
split[i] = token;
i++;
token = strtok(NULL, " ");
}
split[i] = NULL;
}
void read_sentence(struct sentence *a) {
printf("> ");
char str[30];
scanf("%[^.!?\n]s", str);
split(str, a->words, sizeof(a->words));
char temp[1];
scanf("%c", temp);
a->punc = temp[0];
a->next = NULL;
}
int main(int argc, char *argv[]) {
struct sentence *a = malloc(sizeof(struct sentence));
read_sentence(a);
printf("\nfirst contains: %s %s%c\n", a->words[0], a->words[1], a->punc);
struct sentence *b = malloc(sizeof(struct sentence));
printf("\nfirst contains: %s %s%c\n", a->words[0], a->words[1], a->punc);
}
Whenever I run this code the two print statements have different results, the first is correct but the second is empty. I'm at a complete loss as to why this is happening.
The second struct has nothing to do with this.
Your code invokes undefined behavior. You're loading a wrack of dangling pointers into your words
member. All those pointers point to memory within the automatic variable str
in the function read_sentence
, which is gone as soon a read_sentence
returns. The deferences for printing back in main
therefore utilize dangling pointers and thus, UB
I could tell you to provide a dynamic solution to this (dynamic allocation of each word found using strlen
+ malloc
+ memcpy
, or strdup
if you step into the POSIX arena, or we can do it the easy way: make the memory words
refers to tied to the sentence structure itself. Ie Make a str
that belongs to each sentence
, then let words
point to memory in its "sibling" member:
struct sentence {
char line[80]; // <<=== here
char *words[10];
char punc;
struct sentence *next;
};
void split(char *buf, char *split[], size_t max) {
char * token = strtok(buf, " ");
int i = 0;
while (i < max && token != NULL) {
split[i+] = token;
i++;
token = strtok(NULL, " ");
}
split[i] = NULL;
}
void read_sentence(struct sentence *a) {
printf("> ");
scanf("%[^.!?\n]s", a->line); // <<=== HERE
split(a->line, a->words, sizeof a->words / sizeof a->words[0]); // <<=== HERE
a->punc = getchar();
a->next = NULL;
}
int main(int argc, char *argv[])
{
struct sentence *a = malloc(sizeof *a);
read_sentence(a);
printf("\nfirst contains: %s %s%c\n", a->words[0], a->words[1], a->punc);
struct sentence *b = malloc(sizeof *b);
printf("\nfirst contains: %s %s%c\n", a->words[0], a->words[1], a->punc);
free(a);
free(b);
return 0;
}
Worth noting, this is probably more efficient than it first seems. Yes, each sentence gets its own line-buffer, but it doesn't need per-word allocations managing all those strings.
Hope it helps.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.