3

My program worked like it was supposed to until I added the toupper part into my program. I've tried looking at my error code but it's not really helping. The errors are:

no matching function to call 2 arguments expected, one provided

So I know the error is in those two statements in my while loop. What did I do wrong?

I want to make a name like

john brown go to John Brown

#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
using namespace std;

int main(){

  string firstname[5];
  string lastname[5];
  ifstream fin( "data_names.txt" );
  if (!fin) {
    cout << "There is no file" << endl;
  }
  int i = 0;
  while( i < 5 && (fin >> firstname[i]) && (fin >> lastname[i]) ) {
    firstname[0] = toupper(firstname[0]);
    lastname[0] = toupper(lastname[0]);
    i++;
  }
  cout << firstname[0] << " " << lastname [0] << endl;
  cout << firstname[1] << " " << lastname [1] << endl;
  cout << firstname[2] << " " << lastname [2] << endl;
  cout << firstname[3] << " " << lastname [3] << endl;
  cout << firstname[4] << " " << lastname [4] << endl;

  return 0;
}
JOHNSMITH8338
  • 85
  • 2
  • 7
  • Which line is the error pointing to? – wallyk Oct 06 '16 at 21:01
  • 3
    `toupper` expects an `int` you're passing it a `string` - [`toupper` Documentation](http://www.cplusplus.com/reference/cctype/toupper/). – Jonny Henly Oct 06 '16 at 21:02
  • 1
    `toupper` works on a single character at a time. If you want to upper-ize a whole string you need to make a loop that goes through the string applying `toupper` to each character – M.M Oct 06 '16 at 21:03
  • @M.M I want to only uppercase those two letters. How do I highlight those characters of the string and do it correctly? – JOHNSMITH8338 Oct 06 '16 at 21:05
  • @JOHNSMITH8338 which two letters? – M.M Oct 06 '16 at 21:19

2 Answers2

3

std::toupper works on individual characters, but you are trying to apply it to strings. Besides adding #include <cctype>, you need to modify your while loop's body:

firstname[i][0] = toupper(firstname[i][0]);
lastname[i][0] = toupper(lastname[i][0]);
i++;

Then it should work as expected. Live demo here

As M.M helpfully pointed out in the comments, you should also check that your strings aren't empty before accessing their first characters, i.e. something like

if (!firstname[i].empty()) firstname[i][0] = toupper(...);

is strongly recommended.

Mind you, you will probably need more sophisticated logic if you get names like McDonald :)

M.M
  • 138,810
  • 21
  • 208
  • 365
mindriot
  • 5,413
  • 1
  • 25
  • 34
  • 1
    Technically it should be either `toupper( (unsigned char)firstname[i][0] );` (with cctype included), or `toupper( firstname[i][0], std::locale() )` . Also it'd be good to check that the string is not empty for doing `[0]` – M.M Oct 06 '16 at 21:24
  • @M.M I agree. The question's code could benefit from a much more general review. – mindriot Oct 06 '16 at 21:26
  • @mindriot Sorry, I missed the part about including `cctype`. – juanchopanza Oct 06 '16 at 21:29
  • @juanchopanza actually, looks like `cctype` is not even strictly necessary ([demo](http://coliru.stacked-crooked.com/a/4f516162145507d1)), it seems to get pulled in by one of the other headers anyway. – mindriot Oct 06 '16 at 21:33
  • @mindriot Yeah, but that can't be relied upon. BTW that's how the other overload gets pulled in. – juanchopanza Oct 06 '16 at 21:34
  • @JOHNSMITH8338 did this answer your question? If so, you may accept the answer. If not, please let me know. – mindriot Oct 13 '16 at 08:01
2

You need ctype.h to get the proper definition for toupper(). It is usually implemented not as a function, but an array mapping.

 #include <ctype.h>

The program has several flaws: using a string array instead of a string, not iterating through the string correctly, not declaring but using the C definition of toupper(), not exiting when the file does not exist.

Use this instead:

#include <ctype.h>
#include <iostream>
#include <string>
using namespace std;

int main ()
{
  ifstream fin ("data_names.txt");
  if (!fin) 
  {
    cerr << "File missing" << endl;
    return 1;
  }
  // not sure if you were trying to process 5 lines or five words per line
  // but this will process the entire file
  while (!fin.eof())
  {
       string s;
       fin >> s;
       for (i = 0;  i < s.length();  ++i)
            s [i] = toupper (s [i]);
       cout << s << endl;
  }
  return 0;
}
wallyk
  • 56,922
  • 16
  • 83
  • 148
  • I believe it's usually implemented as a function these days, because so many people call it passing plain `char` as argument (which breaks on the array implementation) – M.M Oct 06 '16 at 21:04
  • BTW, the C++ header would be `cctype`, then use `std::toupper`. – juanchopanza Oct 06 '16 at 21:07
  • @juanchopanza won't OP's code still produce errors when not using the 2 parameter C++ overload, since he's passing a `string` when an `int` is expected? – Jonny Henly Oct 06 '16 at 21:07
  • @JonnyHenly Yes, it will. That will be a different error. – juanchopanza Oct 06 '16 at 21:08
  • @juanchopanza what is the correct way to do so? I changed it to: l=lastname[0]; putchar (toupper(l)); f=firstname[0]; putchar (toupper(f)); i++; but still am getting an error. – JOHNSMITH8338 Oct 06 '16 at 21:10
  • @M.M: The original Unix 7 implementation (I think) declared both a function (for function pointer use) and a macro which might expand, depending on implementation to a tertiary evaluation or a mapping array. – wallyk Oct 06 '16 at 21:11
  • @JOHNSMITH8338: What is the exact error text you get? – wallyk Oct 06 '16 at 21:12
  • 1
    @JOHNSMITH8338 Unclear what you're really trying to do but `lastname[0]` is an `std::string`. To get its first character you'd need `lastname[0][0]`. No idea why you're using an array of strings. – juanchopanza Oct 06 '16 at 21:13
  • @juanchopanza My project is to read in full names from a file and then print them into two separate arrays. I want to make john brown to John Brown. I believe I have to use strings. – JOHNSMITH8338 Oct 06 '16 at 21:15
  • @JOHNSMITH8338: Yes, use a `string`, not a string array `string[5]`. – wallyk Oct 06 '16 at 21:15
  • @wallyk he said the code was working properly without `toupper` which suggests the intent is to read 5 pairs of names from the file . (Of course an output loop would be better, but that's another issue) – M.M Oct 06 '16 at 21:26
  • @juanchopanza: There may be some parts that are correct, but I also see a `while (!fin.eof())`... – Jerry Coffin Oct 06 '16 at 22:05
  • @JerryCoffin: Oh yeah, I meant to look that up. – wallyk Oct 06 '16 at 22:20
  • @wallyk: There are a few other things to fix as well. For one, `toupper` can only deal with positive numbers + EOF, but in many character sets, accented characters (and such) will be negative when viewed as `char`s. – Jerry Coffin Oct 06 '16 at 22:27
  • @JerryCoffin Ha! That was added after my votes and discussions. The original had no code. – juanchopanza Oct 07 '16 at 05:55
  • @juanchopanza: Ah, I see--I have to admit, I was a bit surprised, but I didn't think to look through the edit history and compare time stamps. My bad (as they say). – Jerry Coffin Oct 07 '16 at 12:38