I'm having fits with an assignment. Basically, the program is supposed to read in command line arguments and input from a text file and, through a long and convoluted chain of dynamic structures, sort them according to the command line input. The input text file reads as such:
3
"Smith, John" 100
"Jones, Bob" 90
"Willis, Bruce" 75

The first number is read in by a function that stores the size of a set of arrays. The function I'm having trouble with is the one that takes each line after the first (as it has already been read by cin.get) and stores them into 2 variables. Here is the code:

bool readAndParseDataLineFromCIN (char name [], unsigned int & score)
{
  int lineIndex = 0, nameIndex = 0;
  char line[MAX_LINE_LENGTH];
  int quoteCount = 0;
  char numbers[MAX_LINE_LENGTH];
  int counter = 0;

	 // if line does not have 2 quote characters file is invalid

  cin.getline (line, MAX_LINE_LENGTH);  //puts the line into an array. Function will //extract name and score into separate things. Nullterm = '/0'
 
  for (int i; i <= MAX_LINE_LENGTH; i++) //probably garbage right here
  {
	  if (line[i] == '\"')
	  {
		  quoteCount++;
	  }

	  do
	  {
		  name [i] = line[i];
		 
	  } while (quoteCount == 1 && line[i] != '\"');

	 
	  if (quoteCount == 2 && line[i] == '\"')
	  {
		  line[i] = '\0';
	  }

	  do 
	  {
		  numbers[counter] = line[i];
		  counter++;

		  if (quoteCount == 2 && i == MAX_LINE_LENGTH)
		  {
			  numbers[i] = '\0';
		  }
	  } while (quoteCount == 2 && line[i] != '\"');

  }

  score = atoi(numbers);

  for (int j = 0; j <= MAX_LINE_LENGTH; j++)
  {
	  cout << name[j];
  }

  cout << score;

  return quoteCount == 2 && strlen (name) > 0;
  //return true;
}

The idea is to read everything after the quotes from the input file and put the name into an array and the score afterwards into an unsigned int, both of which were passed in the parameters (i.e. '"Smith, John" 100' would be stored into an array as Smith, John and the 100 be stored into an unsigned int). Right now it's returning garbage and I really don't have a clue as to how to get this thing to work properly. I'm sure my loop(s) are horrid, but I really don't know how else to loop this thing properly.

Dani AI

Generated

Diagnosis and quick fixes: the posted function's behaviour comes from undefined/incorrect use of indexes and loop logic (for example for (int i; ...) leaves i uninitialized, <= MAX_LINE_LENGTH can read past the buffer, nested do/while loops overwrite indexes, and the name buffer is not properly null-terminated). Also the newline left after reading the initial count must be consumed before reading subsequent lines. As outlined, the clean, reliable strategy is: find the first quote, find the matching quote, take the substring between them as the name, then skip whitespace and parse the remainder as a number.

A simple, safe C++ implementation using std::string:

bool readAndParseDataLineFromCIN(std::string &name, unsigned int &score)
{
    std::string line;
    if (!std::getline(std::cin, line)) return false;
    auto p1 = line.find('"');
    if (p1 == std::string::npos) return false;
    auto p2 = line.find('"', p1 + 1);
    if (p2 == std::string::npos) return false;
    name = line.substr(p1 + 1, p2 - p1 - 1);
    auto numpos = line.find_first_not_of(" \t", p2 + 1);
    if (numpos == std::string::npos) return false;
    try {
        unsigned long v = std::stoul(line.substr(numpos));
        if (v > std::numeric_limits<unsigned int>::max()) return false;
        score = static_cast<unsigned int>(v);
    } catch (...) { return false; }
    return !name.empty();
}

Notes for the char-array assignment context (): copy the std::string into the provided buffer with strncpy(name, nameStr.c_str(), MAX_NAME_LEN-1); name[MAX_NAME_LEN-1] = '\0';. For numeric parsing on legacy code use strtoul() and check endptr to detect invalid input. Additional troubleshooting: print the raw line during debugging, watch for blank lines, and explicitly discard the leftover newline after reading the initial count (e.g., read the count with operator>> then call std::getline once to consume the rest of that line).

You're making it complicated with two DO loops inside a FOR loop.

Find the first "
Start a while loop until you find the next ", copying the name
Skip past the "
The rest of the line is the number, just use atoi() at that point.

Of course you still have to make sure the second " was found, so you can trap an error.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.