1 2 3 4 5 6 7 8 9 10 11 12 13 14

for (int i = 0; i < 529; i++)
{
f[i][0].x = v[i].x;
f[i][0].y = v[i].y;
f[i][0].z = v[i].y;
f[i][1].x = vn[i].x;
f[i][1].y = vn[i].y;
f[i][1].z = vn[i].y;
f[i][2].x = vt[i].x;
f[i][2].y = vt[i].y;
f[i][2].z = vt[i].y;
}

I think.
Actually, maybe I made it too simple. You have different amounts of verts/normals/textures?
If that is the case then you should also have a set (or two or three) or integers. These integers correspond to the idx array that you just made.
For example, consider a cube:
1 2 3 4 5 6 7 8

v 0,0,0
v 0,0,1
v 0,1,0
v 0,1,1
v 1,0,0
v 1,0,1
v 1,1,0
v 1,1,0

(The order of the vertices is not important for this post.)
But OpenGL can only draw a face of this cube at a time, it needs instructions for what idx to draw: Something that would look like this:
0 1 2 1 2 3 2 3 4 4 5 6 5 6 7 6 7 0 7 0 1
Note that the length of that list is longer than the vertices list. A normal's list can have a different amount of values (a cube it should have 6). However, it's instruction list should be the same length as the vertices instruction list.
So basically. You read the vertices/normals/textures each into there own array (vectors are much easier here). Then read the instructions and fill up the final array. From my example above:
1 2 3 4 5 6 7 8 9 10 11 12 13

std::vector<Point3D> verts;
while (/* the file is reading verts */)
{
Point3d temp;
file >> temp.x >> temp.y >> temp.z;
verts.push_back(temp);
}
std::vector<Point3D> results;
while (/*file is reading instructions*/)
{
results.push_back( temp[instructions] );
}

Also to note that if you have a vector of floats, a float pointer can by simulated via
&results[0]