user7363049
user7363049

Reputation:

How can I store lots of strings with different lengths in the same char array without specifying its size?

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

Answers (3)

Ra'Jiska
Ra'Jiska

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

Sergey Kalinichenko
Sergey Kalinichenko

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

erick orozco
erick orozco

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

Related Questions