cstrings and how to use them question

Hello all. I'm working on a project for a beginner c++ class. I'm tasked with taking a text file, finding each unique word, and outputting those words in ASCII order. Trick is, I am only allowed to use cstrings, not strings. I don't know much about at all of how to cstrings. After reading more about it, I'm still confused!

Below is my code so far. Any help is appreciated!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

// System Libraries
#include <iostream>
#include <iomanip>
#include <cstring>
#include <cctype>
#include <fstream>


// Defined Constants
#define max_words 1000                       // Max words in the list

using namespace std;                         // Standard names will be global

// structs
struct keyword_struct
{
    char index[max_words];    // Word index
    int line_number [max_words];     //counter for line numbers

};

int main() {
     // Local variables
     keyword_struct word_list;
     char         file_name[max_words];               // Input file name
     fstream        file;                    // Input file stream
     char         buffer[max_words];                  // Input buffer for word
     int            size = 0;                // Words in the word list
     int            position = 0;            // Insertion position
     bool           add = false;             // Flag to control insertion

     // Get the input file name from the user
     do {
          file.clear();                      // Clear any residual errors
          cout << "Enter input file name: "; // Prompt the user
          cin.getline(file_name, max_words);
          file.open(file_name,ios::in);      // Attempt to open the file for input
          if(file.good() != true) {          // If file open failed...
               cerr << "?Unable to open \"" << file_name << "\"" << endl;
          }
     } while (file.good() != true);

     // File is open.  Process all words in the file and add them to our list
     while(file.good() == true && file.peek() != EOF) {
          file >> buffer;                    // Read a word from the buffer
          if (file.good() != true) continue; // Error - terminate the loop
          cout << "Word: " << buffer << endl;

          // Scan loop: determine where new word should be inserted
          add = true;                        // Default is to add the word
          for(position = 0; position < size; position++) {
               // Avoid duplicates
               if (buffer == word_list.index) {
                    add = false;        // Don't add to the list
                    break;              // Stop the loop: word already in list
               }

               // Locate insertion point
               if (buffer < word_list.index) {
                    add = true;         // Add to the list
                    break;              // Stop the loop: past desired insertion
               }
          }

          // Make room at word_list[position] and insert the new word
          if (size < (max_words - 1) && add == true) {
               for (int idx = size; idx > position; idx--) {
                    word_list.index[idx] = word_list.index[idx - 1];    // +1 shift to make room
               }
              strcpy(word_list.index, buffer);
              cout << "Added \"" << buffer << "\"" << endl;
               size++;                                      // Increment
          }
     }

     // List is constructed.  Close the file and display the word list
     file.clear();
     file.close();
     for (int idx = 0; idx < size; idx++) {
          cout <<  word_list.index[idx] << endl;
     }

     return 0;
}






c-strings are just arrays. you can do everything you need to here using just a few of the c-string functions that do all the work for you:
strlen //length of a c-string
strcpy //copy a c-string
strcmp //compare a c-string, zero is equal, case matters!
strstr //find a string in a string, and you may not need it here at all

I see
if (buffer == word_list.index) {

which looks wrong, as buffer is a c-string. that should have been strcmp
< just does not work either:
if (buffer < word_list.index) {
etc... you cannot use any operators on c-strings. They are simple arrays, and arrays are just a raw block of bytes, not objects, in c++. (vectors and strings are objects with these capabilities, as you will learn later).

>> to read is fine and to cout etc these work on c-strings fine.
consider
while( file>>buffer) instead of your complicated loop conditions.

and, you have a more basic problem.
char x[10] is a c-string, and it can hold ONE word.
to hold a list of words you need 2-d:
char x[100][10] //100 words, 10 max length.

that translates to needing an array of word-list.
also your words are 1000 long, which will be fine here, but its excessive.

its technically possible to do this in 1-d for an expert with c-strings and pointers but I would not try it. You need to rewrite this to use the 2-d idea. think of it this way … one array of char is a string, and you need an array of strings.
Last edited on
I suggest you start simpler, just read the words from the file into an array of strings, and then print out the array.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
#include <iomanip>
#include <fstream>


// Defined Constants ///////////////////// This is C++ so prefer const over #define.
const size_t MAX_WORDS = 1000;                       // Max words in the list
const size_t MAX_WORD_LENGTH = 100;

// In future try to avoid this, learn to properly scope the namespaces.
using namespace std;                         // Standard names will be global  

int main()
{
    char file_name[MAX_WORD_LENGTH];               // Input file name,

    // Get the input file name from the user
    cout << "Enter input file name: "; // Prompt the user
    cin.getline(file_name, MAX_WORD_LENGTH);
    ifstream file(file_name);   // If just using a file for either input or output prefer ifstream/ofstream.
    if(!file)            // If file open failed... 
    {
        cerr << "?Unable to open \"" << file_name << "\"" << endl;
        return 1;  // Stop program.
    }

    size_t position = 0; 
    char words[MAX_WORDS][MAX_WORD_LENGTH];  // Declare an array of words.
    // When using arrays always insure you don't overflow the arrays. 
    // This is an array of C-strings so you have two arrays to be concerned with, the number of words &&
   //  that the word will fit into the string.
    while(position < MAX_WORDS && file >> std::setw(MAX_WORD_LENGTH) >> words[position])
    {
        position++;
    }

    // Now just print out the words read from the file.
    for(size_t i = 0; i < position; ++i)
        std::cout << words[i] << std::endl;
    std::cout << std::endl;

    return 0;
}
These have been INCREDIBLY helpful to me so far. I've got the code working as I need it right now.

I do have some, albeit probably simple, questions I can't figure out about cstrings. As I mentioned, my old classes never used cstrings, just strings, for our projects, so cstrings are a whole new ballgame for me.

1. cstring arrays - If declared, for example, char my_array [10][100]. This would mean my_array can hold ten lines (vertically, as I picture them in a box graphic) with each line holding up to 100 characters (or 99 with \n). Is this correct?

2. How do I extract just one word from a cstring array?? I understand I can use >> to extract a word, I believe anyways. Would this essentially extract one word, up until a space, from my array and put it in another array?
(ie) char my_array >> my_word;
But then the question of how to print a cstring array. If I'm using cout, do I have to loop it to print out every individual character?

Thanks for any help!!
If declared, for example, char my_array [10][100]. This would mean my_array can hold ten lines (vertically, as I picture them in a box graphic) with each line holding up to 100 characters (or 99 with \n).

It means that you have 10 C-strings of upto 100 characters.

How do I extract just one word from a cstring array?? I understand I can use >> to extract a word, I believe anyways.

The extraction operator>>, when working with a C-string, will extract all characters that appear until it encounters a whitespace character. If you want your string (std::string or C-string) to contain whitespace then you should use getline() instead of the extraction operator. And realize that there are two different getline() functions, one for std::string, the other for C-string.

Would this essentially extract one word, up until a space, from my array and put it in another array?

No the extraction operator requires a stream, an array is not a stream.

But then the question of how to print a cstring array. If I'm using cout, do I have to loop it to print out every individual character?

Look at the example code I provided, I show how to print a complete C-string.

One thing to realize that a C-string is an array of char terminated by the end of string character '\0'.

And this is very important when working with C-strings, never, Never, NEVER use a method that doesn't limit the number of characters it will try to retrieve into a C-string. Not limiting the number of characters to be retrieved is one of the biggest causes of overflowing array bounds. In the sample I provided the setw() function provides the limit for the extraction operator.

Last edited on
How do I extract just one word from a cstring array??

You don't need this here as explained above, but...

you can split with strtok() if you want to dig into this. It can get complex, due to the crude tool. You can also iterate and replace spaces with zeros and and pick off pointers. This is simple and fast but advanced knowledge (simple code, need good understanding of it I mean).

>> and << and getline and so on are wired to work with cstrings for files and console output etc. Remember that string was added many years after c++ came into being, so there is a lot of support for the old way.

c++ is row major. that means rows are first in a 2-d array, and it tells you how memory is laid out as well. so x[rows][columns] is what a 2-d array is like, here rows are words and columns are the chars of the words, but a 2-d of doubles is just one double at some x,y position. Cstring makes this weird because the individual letters being array elements confuses the issue. A single letter is just like the doubles but you don't normally seek out just 1 letter. Try to get this well into your head. Also memory layout.. double[3][3] where the first row is 0,1,2 and the second row is 3,4,5 is stored in memory 012345 in that order -- this is what row major implies. Sometimes that layout is helpful to know, though only in the lowest level code, or pure C code. A column major language (fortran is one) would store 0,3,?,1,4,? (I didn't give a third row)
Last edited on
Topic archived. No new replies allowed.