简体   繁体   中英

Strings & Pointers

I have a question related to strings and pointers. Please explain only with C/C++ programs....

There is a file, which contains 1 word in each line. I knew the no. of words that are there in the file. Please explain with the help of small code, how I can store those words in RAM, efficiently.

Is fscanf(fp,"%s",word) & strcpy , the only way to store the words in RAM... no other efficient algo or logic available..

Thanks.

Probably the most efficient way to do this is to read the whole file into memory in one block (use fread ). Then allocate an array of pointers, one for each word. Then walk through the file in memory, changing the \\n characters to \\0 and storing a pointer the the character after each \\0 in your array.

It is efficient because it only performs one I/O operation, two memory allocations, and loops over the characters in the file twice (once to copy them to the buffer, and once again to break them up into separate strings). The algorithm you describe ( fscanf and strcpy ) will perform many I/O operations, allocate memory for each word, and loops over the characters at least three times (once to read into the buffer, once to find the length to allocate memory for, and once to copy from the buffer into the allocated memory).

Here's a simple version with no error checking:

char* buffer; // pointer to memory that will store the file
char** words; // pointer to memory that will store the word pointers

// pass in FILE, length of file, and number of words
void readfile(FILE *file, int len, int wordcnt)
{
    // allocate memory for the whole file
    buffer = (char*) malloc(sizeof(char) * len);
    // read in the file as a single block
    fread(buffer, 1, size, file);

    // allocate memory for the word list
    words = (char**) malloc(sizeof(char*) * wordcnt);
    int found = 1, // flag indicating if we found a word
                   // (starts at 1 because the file begins with a word)
        curword = 0; // index of current word in the word list

    // create a pointer to the beginning of the buffer
    // and advance it until we hit the end of the buffer
    for (char* ptr = buffer; ptr < buffer + len; ptr++)
    {
        // if ptr points to the beginning of a word, add it to our list
        if (found)
            words[curword++] = ptr;
        // see if the current char in the buffer is a newline
        found = *ptr == '\n';
        // if we just found a newline, convert it to a NUL
        if (found)
            *ptr = '\0';
    }
}

Here's a slightly simpler version using strtok :

char* buffer;
char** words;

void readfile(FILE *file, int len, int wordcnt)
{
    buffer = (char*) malloc(sizeof(char) * len);
    fread(buffer, 1, size, file);
    buffer[len] = '\0';

    words = (char**) malloc(sizeof(char*) * wordcnt);
    int curword = 0;
    char* ptr = strtok(buffer, "\n");
    while (ptr != NULL)
    {
        words[curword++] = ptr;
        ptr = strtok(NULL, "\n");
    }
}

Note that the above two examples assume that the last word in the file ends with a newline!

You could read the entire file into a block of memory, then walk through the block, replacing each '\\r' or '\\n' with a 0. Now you can recover all the strings just by searching through the block for characters immediately following one or more 0's. That's about as space-efficient as you're going to get. Now, if you also want fast access, you could allocate another block of pointers, and set each one to point to the beginning of a string. Still more efficient than a block of pointers each pointing to a separately-allocated String.

If you want your strings not to consume extra not-used bytes, Do this:

char * * array=new char*[COUNT_OF_WORDS];


fscanf(fp,"%s",word);
int len=strlen(word);
array[i]=new char[len+1];
strcpy(array[i],word);

Why strcpy ? Just fscanf directly into the target memory.

Since, you quoted -- "Please explain only with C/C++ programs...." using a vector that holds string is easy - std::vector< std::string >

std::string word;

std::vector < std::string > readWords ;  // A vector to hold the read words.

ifstream myfile ("fileToRead.txt");
if (myfile.is_open())
{
    while ( myfile.good() )
    {
       getline (myfile,word);  // This gets you the first word get copied to line.
       readWords.push_back(word) ; // Each read word is being copied to the vector
    }
    myfile.close();
}

All read words are copied in the vector readWords , you can iterate through it to see what they actually are.

Here's a quick and dirty way to do it, no error checking, using static mem, and using fgets.

#define MAX_NUM_WORDS   10
#define MAX_LEN 128

void get_words(char *p_file, char *words)
{
  FILE *f;

  f = fopen(p_file, "r");
  while (fgets(words, MAX_LEN, f))
    words += MAX_LEN+1;

  fclose(f); 
}

main()
{
  char word_array[MAX_NUM_WORDS][MAX_LEN+1];
  int i;

  get_words("words.txt", word_array);

  for (i=0; i<MAX_NUM_WORDS; i++)
    printf("Word: %s", word_array[i]);
}

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM