Reputation:
I'll implement a dictionary that is basically an array of structures.
Here's the structure:
struct WORD {
char* word;
struct WORD* next;
};
And the array that'll help me reach them:
struct WORD* dictionary[26];
The number 26 stands for 26 letters of the alphabet. We need a linked-list for every single letter, bu that is irrelevant now.
The problem is, I need the char* variable in the structure to be able to store words of different lengths. If I leave it as char*, fscanf fuction doesn't work while reading the words from the file onto the structure. If I make it char word[10] for example, I'd be wasting space for shorter words.
What am I supposed to do?
Upvotes: 4
Views: 2862
Reputation: 1049
You will need to allocate your string dynamically. The function scanf()
can do this for you using the m
format specifier (on POSIX systems that have implemented this feature).
Here is an example:
#include <stdio.h> /* printf, scanf */
#include <stdlib.h> /* free, EXIT */
int main(void)
{
char *str;
fscanf(stdin, "%ms", &str); /* Replace stdin with your FILE * */
printf("%s", str);
free(str);
return EXIT_SUCCESS;
}
Of course you may have noted you need to pass a pointer of your char array to the scanf
function so the array can be allocated.
man 3 scanf
An optional 'm' character. This is used with string conversions (%s, %c, %[), and relieves the caller of the need to allocate a corresponding buffer to hold the input: instead, scanf() allocates a buffer of sufficient size, and assigns the address of this buffer to the corresponding pointer argument, which should be a pointer to a char * variable (this variable does not need to be initialized before the call). The caller should subsequently free(3) this buffer when it is no longer required.
Edit:
As mentioned in comments, the m
flag does not exist in standard C.
The best way I can think of would be read the input using a buffer & realloc
.
Or you could simply use POSIX's getline()
function to get the input (which allocates the string by itself if you need it to).
Upvotes: 0
Reputation: 726509
If I leave it as
char*
,fscanf
function doesn't work
You need to leave it as char*
, and dynamically allocate the string.
Start with a buffer of some large size, say, 1024. Read the word into that buffer using fscanf
with a limit. After that, copy the buffer into a dynamically allocated space for the word:
char buf[1024];
WORD *head = NULL;
while (fscanf(f, "%1023s", buf) == 1) {
size_t len = strlen(buf);
if (!len) continue; // Ignore empty words
WORD *node = malloc(sizeof(WORD));
// Copy the word
node->word = malloc(len+1); // One for '\0' terminator
strcpy(node->word, buf);
// Attach as the new head
node->next = head;
head = node;
}
Note: You can score some points for style with flexible array member: make word
an array with no size, and allocate it together with the node itself, like this:
struct WORD {
struct WORD* next;
char word[];
};
...
char buf[1024];
WORD *head = NULL;
while (fscanf(f, "%1023s", buf) == 1) {
size_t len = strlen(buf);
if (!len) continue; // Ignore empty words
WORD *node = malloc(sizeof(WORD)+len+1);
// Copy the word
strcpy(node->word, buf);
// Attach as the new head
node->next = head;
head = node;
}
Now you have a single allocation instead of two.
Upvotes: 6
Reputation: 13
You can use a temporary buffer with a fixed length and store the word there, so that you can figure out the length. Once you figured out the length, use malloc to allocate the exact number of bytes to the word pointer, and copy it. something like this:
char tempBuffer[20 + 1] = {0}; //Null terminates the string
fsanf(file, "%s", tempBuffer); // read the string
word = (char*) malloc(sizeof(char) * strlen(tempBuffer)); //allocate memory
strcpy(word, (char*) tempBuffer); //copy the string
Upvotes: 1