How to put variables of different datatypes into a struct

Hi,
I have to read an unknown number of variables from a txt file ( this could be 4,8,12 or more variables because it depends on the user) and than I have to put them into a structure.
The txt file looks like this:
datum;numer;number;number;
26.08.2011;0000123;4.567;0000345;
The semicolon is a delimiter. So I can split the string into 4 parts and I can put them out on the screen.
But I have to put them into the struct and I do not know how to do this because the first part of the string is of "String" datatype and the other parts should be integers or double.

My structure looks like this:
1
2
3
4
5
6
7
8
9
structure name_of_struct
{
char *datum;
int  *max;
double *power;
int *min;
};



I have only pointers in the struct because I want it to be dynamic structure.
I know that I have to use "new" to allocate new memory and "delete" to free it.

I hope someone can help me with an advoce or a piece of code because I get no further with my work.
Sorry about my bad english.

Thank you for your time
Pointers do not make it a "dynamic structure", whatever that means. They make it a class that uses aggregation rather than composition.

Use values, e.g.

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
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
using namespace std;
struct name_of_struct
{
    string datum;
    int  max;
    double power;
    int min;
};
int main()
{
    vector<name_of_struct> v;
    ifstream f("test.txt");

    string line;
    while(getline(f, line))
    {
        istringstream str(line);
        name_of_struct item;
        getline(str, item.datum, ';');
        char c;
        str >> item.max >> c >> item.power >> c >> item.min;
        v.push_back(item);
    }

    for(size_t n = 0; n < v.size(); ++n)
    {
        std::cout << "structure number " << n << ": "
                  << v[n].datum << ", " << v[n].max << ", "
                  << v[n].power << ", " << v[n].min << '\n';
    }

}

demo: http://ideone.com/W7ZCe
Last edited on
thank you for the quick response
can you please explain me the same but using dynamic arrays instead of vectors because I have not been working with vectors and it is a bit confusing.
Thank you
I would try it with dynamic arrays, but I do not know how I can replace the vectors by the dynamic array.
Can someone give me an advice please?
The solution of Cubbi is wonderful but I do not want to work with vectors.
I can help you with that matache, but I need to know if there will be multiple lines like you describe, or just one line with an inteterminate number of ';' delimited tokens?
@freddie1
yes in the txt file are multiple lines of the same length.
Thank you for writing me
What is the variable part and what is constant? Is the variable part the number of lines or is the variable part the number of delimited tokens? Or both? For example, is this a possibility....

1
2
3
26.08.2011;0000123;4.567;0000345;
25.07.2012;12345;1.234;9876;5432;123;
24.06.2010;432;1.25


In other words, will there always be three numbers after the initial string? Will the struct you provided with those data types, that is, int, double, int...

1
2
3
4
5
6
7
structure name_of_struct
{
char *datum;
int  *max;
double *power;
int *min;
};


...always reflect what is read from the file? If I understand you correctly, it is. Sorry if I seem to be pressing you too hard for information, but these things are critical to know. Also, what if a line is read from the file with more than three delimited tokens? What should be done with that, or can't that ever happen?
One other question...

26.08.2011;0000123;4.567;0000345;

That line ends in a semicolon delimiter. That's a bit unusual. Why have a delimiter that delimits nothing? Will that always be there?
The lines are always the same length, so they do not get longer or shorter. The number of semicolons and the number of the parts that are delimited by the semicolon is constant.
There is always datum;numer;number:number; and the parts are always the same length.
Yes the number of lines in the txt file is not defined. The txt file could contain more or fewer lines.

Yes there are always three numbers after the string.

Thank you and I hope you can help me further with my work.
This is going to take a lot of code posting by me matache because I seldom use any of the Standard C++ Library functionality. I had to use my own String Class for the parsing functionality (to seperate the semicolon delimited tokens). So I'll be posting all of that. But first, here is the main program and its output. I made a file Data.txt like so...

1
2
3
4
26.08.2011;0000123;4.567;0000345;
25.07.2010;123000;3.14;456;
24.06.2009;45600;3.14159;0789;
23.05.2008;123000;19.95;54321;


Here is the code that loads and parses it along with output...

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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include <windows.h>
#include <cstdio>
#include "Strings.h"
#define  MAX_LINE   1024

struct   Data
{
 char    szDatum[16];
 int     max;
 double  power;
 int     min;
};

int main()
{
 char szLine[MAX_LINE];
 int iParseCount=0;
 char* pChar=NULL;
 String strLine;
 FILE* fp=NULL;
 int iRows=0;

 fp=fopen("Data.txt","r");
 if(fp)
 {
    while(!feof(fp))
    {
       pChar=fgets(szLine,160,fp);
       strLine=szLine;
       strLine.Print(false);
       iRows++;
    }
    printf("\n\niRows            = %d\n",iRows);
    rewind(fp);

    Data* pData=NULL;
    String* pStrs=NULL;
    int blnFree=0;
    pData=(Data*)GlobalAlloc(GPTR,iRows*sizeof(Data));
    if(pData)
    {
       int j=0;
       while(!feof(fp))
       {
          printf("\n");
          pChar=fgets(szLine,160,fp);
          strLine=szLine;
          iParseCount=strLine.ParseCount(';');
          printf("iParseCount      = %d\n",iParseCount);
          pStrs=new String[iParseCount];
          strLine.Parse(pStrs,';');
          strcpy(pData[j].szDatum,pStrs[0].lpStr());
          pData[j].max=pStrs[1].iVal();
          pData[j].power=atof(pStrs[2].lpStr());
          pData[j].min=pStrs[3].iVal();
          printf("pData[%d].szDatum = %s\n",j,pData[j].szDatum);
          printf("pData[%d].max     = %d\n",j,pData[j].max);
          printf("pData[%d].power   = %f\n",j,pData[j].power);
          printf("pData[%d].min     = %d\n",j,pData[j].min);
          delete [] pStrs;
          j++;
       }

       printf("\n");
       printf("i\tszDatum\t\tmax\tpower\t\tmin\n");
       printf("=======================================================\n");
       for(int i=0; i<iRows; i++)
           printf("%d\t%s\t%d\t%f\t%d\n",i,pData[i].szDatum,pData[i].max,pData[i].power,pData[i].min);

       blnFree=(int)GlobalFree(pData);
       printf("\nblnFree = %d  (zero is good)\n",blnFree);

    }
    fclose(fp);
 }
 getchar();

 return 0;
}

/*
26.08.2011;0000123;4.567;0000345;
25.07.2010;123000;3.14;456;
24.06.2009;45600;3.14159;0789;
23.05.2008;123000;19.95;54321;

iRows            = 4

iParseCount      = 5
pData[0].szDatum = 26.08.2011
pData[0].max     = 123
pData[0].power   = 4.567000
pData[0].min     = 345

iParseCount      = 5
pData[1].szDatum = 25.07.2010
pData[1].max     = 123000
pData[1].power   = 3.140000
pData[1].min     = 456

iParseCount      = 5
pData[2].szDatum = 24.06.2009
pData[2].max     = 45600
pData[2].power   = 3.141590
pData[2].min     = 789

iParseCount      = 5
pData[3].szDatum = 23.05.2008
pData[3].max     = 123000
pData[3].power   = 19.950000
pData[3].min     = 54321

i       szDatum         max     power           min
=======================================================
0       26.08.2011      123     4.567000        345
1       25.07.2010      123000  3.140000        456
2       24.06.2009      45600   3.141590        789
3       23.05.2008      123000  19.950000       54321


blnFree = 0  (zero is good)
*/
Last edited on
Here is the header for my string class...

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
//Strings.h
#if !defined(STRINGS_H)
#define STRINGS_H
#define EXPANSION_FACTOR      2
#define MINIMUM_ALLOCATION   16

class String
{
 public:
 friend String operator+(TCHAR*, String&);
 String();                                    //Uninitialized Constructor
 String(const TCHAR);                         //Constructor Initializes With A TCHAR.
 String(const TCHAR*);                        //Constructor Initializes String With TCHAR*
 String(const String&);                       //Constructor Initializes String With Another String (Copy Constructor)
 String(const int, bool);                     //Constructor Creates String With User Specified Capacity and optionally nulls out
 String(const int, const TCHAR);              //Constructor initializes String with int # of TCHARs
 String(int);                                 //Constructor initializes String with int converted to String
 String(unsigned int);                        //Constructor initializes String with unsigned int converted to String
 String(double);                              //Constructor initializes String with double converted to String
 String& operator=(const TCHAR);              //Assign A TCHAR To A String
 String& operator=(const TCHAR*);             //Assign A Null Terminated TCHARacter Array To A String
 String& operator=(const String&);            //Assigns Another String To this One
 String& operator=(int iNum);                 //Assigns an unsigned int to a String
 String& operator=(unsigned int iNum);        //Assigns an unsigned int to a String
 String& operator=(double dblNum);            //Assign a double to a String
 String operator+(const TCHAR);               //For adding TCHAR to String
 String operator+(const TCHAR*);              //Adds a TCHAR* to this
 String operator+(String&);                   //Adds another String to this
 String& operator+=(const TCHAR ch);          //Add TCHAR to this
 String& operator+=(const String&);           //Adds a String to this and assigns it to left of equal sign
 String& operator+=(const TCHAR*);            //Adds a TCHAR*to this and assigns it to left of equal sign
 bool operator==(String&);                    //Compares Strings For Case Sensitive Equality
 bool operator==(const TCHAR*);               //Compares String Against TCHAR* For Case Sensitive Equality
 String& Make(const TCHAR ch, int iCount);    //Returns reference to this with iCount ch TCHARs in it
 String Left(int);                            //Returns String of iNum Left Most TTCHARs of this
 String Right(int);                           //Returns String of iNum Right Most TTCHARs of this
 String Mid(int, int);                        //Returns String consisting of number of TTCHARs from some offset
 String Replace(TCHAR*, TCHAR*);              //Returns String with 1st TCHAR* parameter replaced with 2nd TCHAR* parameter
 String Remove(TCHAR*);                       //Returns A String With All The TCHARs In A TCHAR* Removed (Individual TCHAR removal)
 String Remove(const TCHAR*, bool);           //Returns a String with 1st parameter removed.  2nd is bool for case sensitivity.
 int InStr(const TCHAR*, bool);               //Returns one based offset of a particular TTCHAR pStr in a String
 int InStr(const String&, bool);              //Returns one based offset of where a particular String is in another String
 int ParseCount(const TCHAR);                 //Returns count of Strings delimited by a TTCHAR passed as a parameter
 void Parse(String*, TCHAR);                  //Returns array of Strings in first parameter as delimited by 2nd TTCHAR delimiter
 void SetTCHAR(int, TCHAR);                   //Sets TCHAR at zero based offset in this
 void LTrim();                                //Returns String with leading spaces/tabs removed
 void RTrim();                                //Returns String with spaces/tabs removed from end
 void Trim();                                 //Returns String with both leading and trailing whitespace removed
 int iVal();                                  //Returns integral value of String
 int Len();                                   //Returns Length Of String Controlled By this
 int Capacity();                              //Returns Maximum Permissable TCHARacter Count (One Less Than Allocation).
 TCHAR* lpStr();                              //Returns TCHAR* To String
 void Print(bool);                            //Outputs String To Console With Or Without CrLf.
 ~String();                                   //String Destructor

 private:
 TCHAR* lpBuffer;
 int   iLen;
 int   iCapacity;
};

String operator+(TCHAR* lhs, String& rhs);
#endif  //#if !defined(STRINGS_H) 

Now I'll start posting Strings.cpp. It'll take several posts. You'll have to paste them together.

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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
//Strings.cpp
//#define UNICODE
//#define _UNICODE
#include  <stdlib.h>
#include  <stdio.h>
#include  <tchar.h>
#include  <math.h>
#include  <string.h>
#include  "Strings.h"


String operator+(TCHAR* lhs, String& rhs)         //global function
{
 String sr=lhs;
 sr=sr+rhs;

 return sr;
}


String::String()
{
 lpBuffer=new TCHAR[MINIMUM_ALLOCATION];
 lpBuffer[0]=_T('\0');
 this->iCapacity=MINIMUM_ALLOCATION-1;
 this->iLen=0;
}


String::String(const TCHAR ch)  //Constructor: Initializes with TCHAR
{
 this->iLen=1;
 int iNewSize=MINIMUM_ALLOCATION;
 this->lpBuffer=new TCHAR[iNewSize];
 this->iCapacity=iNewSize-1;
 this->lpBuffer[0]=ch, this->lpBuffer[1]=_T('\0');
}


String::String(const TCHAR* pStr)  //Constructor: Initializes with TCHAR*
{
 this->iLen=_tcslen(pStr);
 int iNewSize=(this->iLen/16+1)*16;
 this->lpBuffer=new TCHAR[iNewSize];
 this->iCapacity=iNewSize-1;
 _tcscpy(lpBuffer,pStr);
}


String::String(const String& s)  //Constructor Initializes With Another String, i.e., Copy Constructor
{
 int iNewSize=(s.iLen/16+1)*16;
 this->iLen=s.iLen;
 this->lpBuffer=new TCHAR[iNewSize];
 this->iCapacity=iNewSize-1;
 _tcscpy(this->lpBuffer,s.lpBuffer);
}


String::String(const int iSize, bool blnFillNulls)  //Constructor Creates String With Custom Sized
{                                                   //Buffer (rounded up to paragraph boundary)
 int iNewSize=(iSize/16+1)*16;
 this->lpBuffer=new TCHAR[iNewSize];
 this->iCapacity=iNewSize-1;
 this->iLen=0;
 this->lpBuffer[0]=_T('\0');
 if(blnFillNulls)
 {
    for(int i=0; i<this->iCapacity; i++)
        this->lpBuffer[i]=0;
 }
}


String::String(int iCount, const TCHAR ch)
{
 int iNewSize=(iCount/16+1)*16;
 this->lpBuffer=new TCHAR[iNewSize];
 this->iCapacity=iNewSize-1;
 for(int i=0; i<iCount; i++)
     this->lpBuffer[i]=ch;
 this->lpBuffer[iCount]=_T('\0');
 this->iLen=iCount;
}


String::String(int iNum)
{
 this->lpBuffer=new TCHAR[16];
 this->iCapacity=15;
 this->iLen=_stprintf(this->lpBuffer,_T("%d"),iNum);
}


String::String(unsigned int iNum)
{
 this->lpBuffer=new TCHAR[16];
 this->iCapacity=15;
 this->iLen=_stprintf(this->lpBuffer,_T("%u"),iNum);
}


String::String(double dblNum)
{
 this->lpBuffer=new TCHAR[32];
 this->iCapacity=31;
 this->iLen=_stprintf(this->lpBuffer,_T("%10.14f"),dblNum);
}


String& String::operator=(double dblNum)
{
 if(this->iCapacity<32)
 {
    delete [] this->lpBuffer;
    lpBuffer=new TCHAR[32];
    this->iCapacity=31;
 }
 this->iLen=_stprintf(this->lpBuffer,_T("%10.14f"),dblNum);

 return *this;
}


void String::SetTCHAR(int iOffset, TCHAR ch)   //zero based!
{
 if(iOffset<this->iCapacity)
 {
    this->lpBuffer[iOffset]=ch;
    if(ch==_T('\0'))
    {
       if(iOffset<this->iLen || this->iLen==0)
          this->iLen=iOffset;
    }
 }
}


String& String::operator=(const TCHAR ch)
{
 this->lpBuffer[0]=ch, this->lpBuffer[1]=_T('\0');
 this->iLen=1;
 return *this;
}


String& String::operator=(const TCHAR* pStr)
{
 int iNewLen=_tcslen(pStr);
 if(iNewLen>this->iCapacity)
 {
    delete [] this->lpBuffer;
    int iNewSize=(iNewLen*EXPANSION_FACTOR/16+1)*16;
    this->lpBuffer=new TCHAR[iNewSize];
    this->iCapacity=iNewSize-1;
 }
 _tcscpy(this->lpBuffer,pStr);
 this->iLen=iNewLen;

 return *this;
}


String& String::operator=(const String& strAnother)
{
 if(this==&strAnother)
    return *this;
 if(strAnother.iLen>this->iCapacity)
 {
    delete [] this->lpBuffer;
    int iNewSize=(strAnother.iLen*EXPANSION_FACTOR/16+1)*16;
    this->lpBuffer=new TCHAR[iNewSize];
    this->iCapacity=iNewSize-1;
 }
 _tcscpy(this->lpBuffer,strAnother.lpBuffer);
 this->iLen=strAnother.iLen;

 return *this;
}


String& String::operator=(int iNum)
{
 if(this->iCapacity>=15)
    this->iLen=_stprintf(this->lpBuffer,_T("%d"),iNum);
 else
 {
    delete [] this->lpBuffer;
    this->lpBuffer=new TCHAR[16];
    this->iCapacity=15;
    this->iLen=_stprintf(this->lpBuffer,_T("%d"),iNum);
 }

 return *this;
}


String& String::operator=(unsigned int iNum)
{
  if(this->iCapacity>=15)
    this->iLen=_stprintf(this->lpBuffer,_T("%d"),iNum);
 else
 {
    delete [] this->lpBuffer;
    this->lpBuffer=new TCHAR[16];
    this->iCapacity=15;
    this->iLen=_stprintf(this->lpBuffer,_T("%d"),iNum);
 }

 return *this;
}


String String::operator+(const TCHAR ch)
{
 int iNewLen=this->iLen+1;

 String s(iNewLen,false);
 _tcscpy(s.lpBuffer,this->lpBuffer);
 s.lpBuffer[iNewLen-1]=ch;
 s.lpBuffer[iNewLen]=_T('\0');
 s.iLen=iNewLen;

 return s;
}


String String::operator+(const TCHAR* pStr)
{
 int iNewLen=_tcslen(pStr)+this->iLen;
 String s(iNewLen,false);
 _tcscpy(s.lpBuffer,this->lpBuffer);
 _tcscat(s.lpBuffer,pStr);
 s.iLen=iNewLen;

 return s;
}


String String::operator+(String& strRef)
{
 int iNewLen=strRef.iLen+this->iLen;
 String s(iNewLen,false);
 _tcscpy(s.lpBuffer,this->lpBuffer);
 _tcscat(s.lpBuffer,strRef.lpBuffer);
 s.iLen=iNewLen;

 return s;
}


String& String::operator+=(const TCHAR ch)
{
 int iTot=this->iLen+1;
 if(iTot>this->iCapacity)
 {
    int iNewSize=(iTot*EXPANSION_FACTOR/16+1)*16;
    TCHAR* pNew=new TCHAR[iNewSize];
    _tcscpy(pNew,this->lpBuffer);
    delete [] this->lpBuffer;
    this->lpBuffer=pNew;
    this->lpBuffer[iTot-1]=ch;
    this->lpBuffer[iTot]=_T('\0');
    this->iCapacity=iNewSize-1;
    this->iLen=iTot;
 }
 else
 {
    this->lpBuffer[iTot-1]=ch;
    this->lpBuffer[iTot]=_T('\0');
    this->iLen=iTot;
 }
 return *this;
}


String& String::operator+=(const TCHAR* pStr)
{
 int iStrlen=_tcslen(pStr);
 int iTot=iStrlen+this->iLen;
 if(iTot>this->iCapacity)
 {
    int iNewSize=(iTot*EXPANSION_FACTOR/16+1)*16;
    TCHAR* pNew=new TCHAR[iNewSize];
    _tcscpy(pNew,this->lpBuffer);
    delete [] this->lpBuffer;
    this->lpBuffer=pNew;
    _tcscat(pNew,pStr);
    this->iCapacity=iNewSize-1;
    this->iLen=iTot;
 }
 else
 {
    _tcscat(this->lpBuffer,pStr);
    this->iLen=iTot;
 }
 return *this;
}


String& String::operator+=(const String& strRef)
{
 int iTot=strRef.iLen+this->iLen;
 if(iTot>this->iCapacity)
 {
    int iNewSize=(iTot*EXPANSION_FACTOR/16+1)*16;
    TCHAR* pNew=new TCHAR[iNewSize];
    _tcscpy(pNew,this->lpBuffer);
    delete [] this->lpBuffer;
    this->lpBuffer=pNew;
    _tcscat(pNew,strRef.lpBuffer);
    this->iCapacity=iNewSize-1;
    this->iLen=iTot;
 }
 else
 {
    _tcscat(this->lpBuffer,strRef.lpBuffer);
    this->iLen=iTot;
 }
 return *this;
}


bool String::operator==(String& strRef)
{
 if(_tcscmp(this->lpStr(),strRef.lpStr())==0)
    return true;
 else
    return false;
}


bool String::operator==(const TCHAR* pStr)
{
 if(_tcscmp(this->lpStr(),pStr)==0)
    return true;
 else
    return false;
}


String& String::Make(const TCHAR ch, int iCount)    //Creates (Makes) a String with iCount TCHARs
{
 if(iCount>this->iCapacity)
 {
    delete [] lpBuffer;
    int iNewSize=(iCount*EXPANSION_FACTOR/16+1)*16;
    this->lpBuffer=new TCHAR[iNewSize];
    this->iCapacity=iNewSize-1;
 }
 for(int i=0; i<iCount; i++)
     this->lpBuffer[i]=ch;
 this->lpBuffer[iCount]=0;
 this->iLen=iCount;
 return *this;
}


String String::Left(int iNum)   //  strncpy = _tcsncpy
{
 if(iNum<this->iLen)
 {
    int iNewSize=(iNum*EXPANSION_FACTOR/16+1)*16;
    String sr(iNewSize,false);
    _tcsncpy(sr.lpBuffer,this->lpBuffer,iNum);
    sr.lpBuffer[iNum]=0;
    sr.iLen=iNum;
    return sr;
 }
 else
 {
    String sr=*this;
    return sr;
 }
}


continued...

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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
String String::Right(int iNum)  //Returns Right$(strMain,iNum)
{
 if(iNum<this->iLen)
 {
    int iNewSize=(iNum*EXPANSION_FACTOR/16+1)*16;
    String sr(iNewSize,false);
    _tcsncpy(sr.lpBuffer,this->lpBuffer+this->iLen-iNum,iNum);
    sr.lpBuffer[iNum]=_T('\0');
    sr.iLen=iNum;
    return sr;
 }
 else
 {
    String sr=*this;
    sr.iLen=this->iLen;
    return sr;
 }
}


String String::Mid(int iStart, int iCount)
{
 if(iStart<1)
 {
    String sr;
    return sr;
 }
 if(iCount+iStart>this->iLen)
    iCount=this->iLen-iStart+1;
 String sr(iCount,false);
 _tcsncpy(sr.lpBuffer,this->lpBuffer+iStart-1,iCount);
 sr.lpBuffer[iCount]=_T('\0');
 sr.iLen=iCount;

 return sr;
}


String String::Replace(TCHAR* pMatch, TCHAR* pNew)  //strncmp = _tcsncmp
{
 int i,iLenMatch,iLenNew,iCountMatches,iExtra,iExtraLengthNeeded,iAllocation,iCtr;
 iLenMatch=_tcslen(pMatch);
 iCountMatches=0, iAllocation=0, iCtr=0;
 iLenNew=_tcslen(pNew);
 if(iLenNew==0)
 {
    String sr=this->Remove(pMatch,true); //return
    return sr;
 }
 else
 {
    iExtra=iLenNew-iLenMatch;
    for(i=0; i<this->iLen; i++)
    {
        if(_tcsncmp(lpBuffer+i,pMatch,iLenMatch)==0)
           iCountMatches++;  //Count how many match strings
    }
    iExtraLengthNeeded=iCountMatches*iExtra;
    iAllocation=this->iLen+iExtraLengthNeeded;
    String sr(iAllocation,false);
    for(i=0; i<this->iLen; i++)
    {
        if(_tcsncmp(this->lpBuffer+i,pMatch,iLenMatch)==0)
        {
           _tcscpy(sr.lpBuffer+iCtr,pNew);
           iCtr+=iLenNew;
           i+=iLenMatch-1;
        }
        else
        {
           sr.lpBuffer[iCtr]=this->lpBuffer[i];
           iCtr++;
        }
        sr.lpBuffer[iCtr]=_T('\0');
    }
    sr.iLen=iCtr;
    return sr;
 }
}


String String::Remove(TCHAR* pStr)
{
 unsigned int i,j,iStrLen,iParamLen;
 TCHAR *pThis, *pThat, *p;
 bool blnFoundBadTCHAR;

 iStrLen=this->iLen;               //The length of this
 String sr((int)iStrLen,false);    //Create new String big enough to contain original String (this)
 iParamLen=_tcslen(pStr);          //Get length of parameter (pStr) which contains TCHARs to be removed
 pThis=this->lpBuffer;
 p=sr.lpStr();
 for(i=0; i<iStrLen; i++)
 {
     pThat=pStr;
     blnFoundBadTCHAR=false;
     for(j=0; j<iParamLen; j++)
     {
         if(*pThis==*pThat)
         {
            blnFoundBadTCHAR=true;
            break;
         }
         pThat++;
     }
     if(!blnFoundBadTCHAR)
     {
        *p=*pThis;
         p++;
        *p=_T('\0');
     }
     pThis++;
 }
 sr.iLen=_tcslen(sr.lpStr());

 return sr;
}


String String::Remove(const TCHAR* pMatch, bool blnCaseSensitive)
{
 int i,iCountMatches=0,iCtr=0;

 int iLenMatch=_tcslen(pMatch);
 for(i=0; i<this->iLen; i++)
 {
     if(blnCaseSensitive)
     {
        if(_tcsncmp(lpBuffer+i,pMatch,iLenMatch)==0)  //_tcsncmp
           iCountMatches++;
     }
     else
     {
        if(_tcsnicmp(lpBuffer+i,pMatch,iLenMatch)==0) //__tcsnicmp
           iCountMatches++;
     }
 }
 int iAllocation=this->iLen-(iCountMatches*iLenMatch);
 String sr(iAllocation,false);
 for(i=0; i<this->iLen; i++)
 {
     if(blnCaseSensitive)
     {
        if(_tcsncmp(this->lpBuffer+i,pMatch,iLenMatch)==0)
           i+=iLenMatch-1;
        else
        {
           sr.lpBuffer[iCtr]=this->lpBuffer[i];
           iCtr++;
        }
        sr.lpBuffer[iCtr]=_T('\0');
     }
     else
     {
        if(_tcsnicmp(this->lpBuffer+i,pMatch,iLenMatch)==0)
           i+=iLenMatch-1;
        else
        {
           sr.lpBuffer[iCtr]=this->lpBuffer[i];
           iCtr++;
        }
        sr.lpBuffer[iCtr]=_T('\0');
     }
 }
 sr.iLen=iCtr;
 return sr;
}


int String::ParseCount(const TCHAR c)  //returns one more than # of
{                                      //delimiters so it accurately
 int iCtr=0;                           //reflects # of strings delimited
 TCHAR* p;                             //by delimiter.

 p=this->lpBuffer;
 while(*p)
 {
  if(*p==c)
     iCtr++;
  p++;
 }

 return ++iCtr;
}


void String::Parse(String* pStr, TCHAR delimiter)
{
 unsigned int i=0;
 TCHAR* pBuffer=0;
 TCHAR* c;
 TCHAR* p;

 pBuffer=new TCHAR[this->iLen+1];
 if(pBuffer)
 {
    p=pBuffer;
    c=this->lpBuffer;
    while(*c)
    {
       if(*c==delimiter)
       {
          pStr[i]=pBuffer;
          p=pBuffer;
          i++;
       }
       else
       {
          *p=*c;
          p++;
          *p=0;
       }
       c++;
    }
    pStr[i]=pBuffer;
    delete [] pBuffer;
 }
}


int String::InStr(const TCHAR* pStr, bool blnCaseSensitive)
{
 int i,iParamLen,iRange;

 if(*pStr==0)
    return 0;
 iParamLen=_tcslen(pStr);
 iRange=this->iLen-iParamLen;
 if(iRange>=0)
 {
    for(i=0;i<=iRange;i++)
    {
        if(blnCaseSensitive)
        {
           if(_tcsncmp(lpBuffer+i,pStr,iParamLen)==0)   //_tcsncmp
              return i+1;
        }
        else
        {
           if(_tcsnicmp(lpBuffer+i,pStr,iParamLen)==0)  //__tcsnicmp
              return i+1;
        }
    }
 }

 return 0;
}


int String::InStr(const String& s, bool blnCaseSensitive)
{
 int i,iParamLen,iRange;

 if(s.iLen==0)
    return 0;
 iParamLen=s.iLen;
 iRange=this->iLen-iParamLen;
 if(iRange>=0)
 {
    for(i=0; i<=iRange; i++)
    {
        if(blnCaseSensitive)
        {
           if(_tcsncmp(this->lpBuffer+i,s.lpBuffer,iParamLen)==0)  //_tcsncmp
              return i+1;
        }
        else
        {
           if(_tcsnicmp(this->lpBuffer+i,s.lpBuffer,iParamLen)==0) //__tcsnicmp
              return i+1;
        }
    }
 }

 return 0;
}


void String::LTrim()
{
 int iCt=0;

 for(int i=0; i<this->iLen; i++)
 {
     if(this->lpBuffer[i]==32 || this->lpBuffer[i]==9)
        iCt++;
     else
        break;
 }
 if(iCt)
 {
    for(int i=iCt; i<=this->iLen; i++)
        this->lpBuffer[i-iCt]=this->lpBuffer[i];
 }
 this->iLen=this->iLen-iCt;
}


void String::RTrim()
{
 int iCt=0;

 for(int i=this->iLen-1; i>0; i--)
 {
     if(this->lpBuffer[i]==9||this->lpBuffer[i]==10||this->lpBuffer[i]==13||this->lpBuffer[i]==32)
        iCt++;
     else
        break;
 }
 this->lpBuffer[this->iLen-iCt]=0;
 this->iLen=this->iLen-iCt;
}


void String::Trim()
{
 this->LTrim();
 this->RTrim();
}


int String::iVal()
{
 return _ttoi(this->lpBuffer);  //_ttoi
}


int String::Len(void)
{
 return this->iLen;
}


int String::Capacity(void)
{
 return this->iCapacity;
}


TCHAR* String::lpStr()
{
 return lpBuffer;
}


void String::Print(bool blnCrLf)
{
 _tprintf(_T("%s"),lpBuffer);
 if(blnCrLf)
    _tprintf(_T("\n"));
}


String::~String()   //String Destructor
{
 delete [] lpBuffer;
 lpBuffer=0;
}
Feel free to ask questions about any part of it.
OMG!
I will try to understand your code because I am a newbie in C++.
Thank you very much for your time and help. I will post questions when I get stuck with the code.
I better get to work now.
THANK YOU AGAIN!
Don't try to understand the String Class or you'll likely get bogged down. Just treat it as a 'black box' that performs some useful functionality for you - specifically, parsing a string containing delimiters into sub-strings.

To understand the program you need to understand pointers, memory allocation, and data conversion. For the Data struct which contains your parsed line I allocated four of those - each 32 bytes, to hold the data for each line read out of the file. I could have used 'new', but I didn't. Instead I created the dynamic memory block with the Win32 function GlobalAlloc. There are piles of memory allocation functions - some part of the OS and others part of C or C++.
I hate to see folks struggle like I did when learning this stuff, but there's no other way for a lot of it. I added comments to the program that will hopefully help. Here's the program with comments...

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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include <windows.h>
#include <cstdio>
#include "Strings.h"
#define  MAX_LINE   1024

struct   Data
{
 char    szDatum[16];    // Can hold up to 15 chars + 1 for null
 int     max;            // I could have used one of my String Class
 double  power;          // objects to hold the string, but thought
 int     min;            // a char array would be simpler to understand.
};

int main()
{
 char szLine[MAX_LINE];  // gets (get string) requires a buffer into which the string goes
 int iParseCount=0;      // used to hold the number of sub strings delimited by some delimiter
 char* pChar=NULL;       // if gets successfully reads a line, this won't be null.
 String strLine;         // one of my String Class objects to hold a line read into program
 FILE* fp=NULL;          // low level FILE pointer
 int iRows=0;            // will hold count of lines read in from file

 fp=fopen("Data.txt","r");   // open file, but only process if fp isn't null.
 if(fp)
 {
    while(!feof(fp))         // feof tests for end of file
    {
       pChar=fgets(szLine,160,fp);   // read line from file
       strLine=szLine;               // assign to string object
       strLine.Print(false);         // output to console
       iRows++;                      // count line
    }
    printf("\n\niRows            = %d\n",iRows);
    rewind(fp);                      // restore file pointer to beginning of file

    Data* pData=NULL;     // declare a pointer that can point to a Data object
    String* pStrs=NULL;   // declare a pointer that can point to String objects
    int blnFree=0;
    pData=(Data*)GlobalAlloc(GPTR,iRows*sizeof(Data));   // allocate memory for iRows Data objects.
    if(pData)                                            // the idea here is to re-run through the file again
    {                                                    // and use String::Parse() to retrieve the ';'
       int j=0;                                          // delimited sub-strings.  String::ParseCount() will
       while(!feof(fp))                                  // return the number of delimited Strings.  This number
       {                                                 // must then be used to dynamically allocate iParseCount
          printf("\n");                                  // String Objects into which String::Parse() will store
          pChar=fgets(szLine,160,fp);                    // the delimited sub strings.  Note I needed to use
          strLine=szLine;                                // strcpy() (C Runtime Function) to copy the String
          iParseCount=strLine.ParseCount(';');           // buffer of my String Class Object to the Data::szDatum
          printf("iParseCount      = %d\n",iParseCount); // buffer in the Data object.  I also needed to use the
          pStrs=new String[iParseCount];                 // atof function to convert the floating point string
          strLine.Parse(pStrs,';');                      // to the numeric format.  After each line is read in
          strcpy(pData[j].szDatum,pStrs[0].lpStr());     // I destroy the String Object pStrs.  If you could be
          pData[j].max=pStrs[1].iVal();                  // certain the line won't contain more than five
          pData[j].power=atof(pStrs[2].lpStr());         // sub-strings, you could keep re-using the same pStrs
          pData[j].min=pStrs[3].iVal();                  // object instead or re-creating it and destroying it
          printf("pData[%d].szDatum = %s\n",j,pData[j].szDatum);   // with every iteration of the while loop.
          printf("pData[%d].max     = %d\n",j,pData[j].max);       // But if you did that and for some unknown
          printf("pData[%d].power   = %f\n",j,pData[j].power);     // reason a line would be read in containing
          printf("pData[%d].min     = %d\n",j,pData[j].min);       // even one more string, you would instantly
          delete [] pStrs;                                         // crash and burn.
          j++;
       }

       printf("\n");
       printf("i\tszDatum\t\tmax\tpower\t\tmin\n");
       printf("=======================================================\n");
       for(int i=0; i<iRows; i++)
           printf("%d\t%s\t%d\t%f\t%d\n",i,pData[i].szDatum,pData[i].max,pData[i].power,pData[i].min);

       blnFree=(int)GlobalFree(pData);
       printf("\nblnFree = %d  (zero is good)\n",blnFree);

    }
    fclose(fp);
 }
 getchar();

 return 0;
}

/*
26.08.2011;0000123;4.567;0000345;
25.07.2010;123000;3.14;456;
24.06.2009;45600;3.14159;0789;
23.05.2008;123000;19.95;54321;

iRows            = 4

iParseCount      = 5
pData[0].szDatum = 26.08.2011
pData[0].max     = 123
pData[0].power   = 4.567000
pData[0].min     = 345

iParseCount      = 5
pData[1].szDatum = 25.07.2010
pData[1].max     = 123000
pData[1].power   = 3.140000
pData[1].min     = 456

iParseCount      = 5
pData[2].szDatum = 24.06.2009
pData[2].max     = 45600
pData[2].power   = 3.141590
pData[2].min     = 789

iParseCount      = 5
pData[3].szDatum = 23.05.2008
pData[3].max     = 123000
pData[3].power   = 19.950000
pData[3].min     = 54321

i       szDatum         max     power           min
=======================================================
0       26.08.2011      123     4.567000        345
1       25.07.2010      123000  3.140000        456
2       24.06.2009      45600   3.141590        789
3       23.05.2008      123000  19.950000       54321


blnFree = 0  (zero is good)
*/
That compiles to 27648 bytes using Code::Blocks 10.05 and MinGW. Size on disk 28672. Had I used the C++ Std Libs string class I'd have been up to likely around 50 K. Had I used the C++ Std Libs iostream for console output I'd have been up to 400 K for the dumb thing.

Just out of curiousity I did the exact same program in PowerBASIC, which is a high performance Win32 compiler, and unbelievably enough I came up with almost the same exact numbers. I got 27136 and a size on disk of 28672. The size on disk was exactly the same but the PowerBASIC exe was about 500 bytes smaller.

Just to provide an example of how something like this looks in another language (and one a lot easier to learn and code in) here is my PowerBASIC program and its output using the same Data.txt file...

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
#Compile Exe
#Dim All

Type MyData
  szDatum  As  Asciiz*16
  iMax     As  Long
  dblPower As  Double
  iMin     As  Long
End Type

Function PBMain() As Long
  Local strFields() As String            'PowerBASIC and most or all versions of Basic dialects
  Local arData() As MyData               'in Windows allocate String Objects using the OLE
  Local strLine As String                'String Engine.  The actual C/C++ data type is BSTR.
  Local fp, iRows As Long                'Here, arData, i.e., read 'Array Data', is a dynamically
  Register i As Long                     'allocated array of MyData type.  All this could have
                                         'been done with pointers, but wy bother if it can be done
  fp=Freefile                            'easier????
  Open "Data.txt" For Input As #fp
  FileScan #fp, Records To iRows         'Puts # of rows in iRows
  Con.Print "iRows = " iRows : Print     'With PowerBASIC you can dynamically allocate arrays
  Redim arData(iRows) As MyData          'of any number of dimensions of any user defined type
  For i=1 To iRows
    Line Input #fp, strLine              'strFields() will be dynamically rediminsioned with each line
    Print strLine                        'to hold the number of sub strings parsed out of a line.
    Redim strFields(ParseCount(strLine, ";")) As String  'Function call within a function call
    Parse strLine, strFields(), ";"                      'Parse fields into strFields() using ';'
    arData(i-1).szDatum=strFields(0)                     'Assign data to MyData.  PowerBASIC uses
    arData(i-1).iMax=Val(strFields(1))                   'a Val function to convert a String to
    arData(i-1).dblPower=Val(strFields(2))               'a numeric value
    arData(i-1).iMin=Val(strFields(3))
    erase strFields()
  Next i
  Con.Print
  Con.Print " i            szDatum        iMax          dblPower      iMin"
  Con.Print "============================================================="
  For i=1 To iRows
    Con.Print i, arData(i-1).szDatum, arData(i-1).iMax, arData(i-1).dblPower, arData(i-1).iMin
  Next i
  Erase arData
  Close #fp
  Con.Waitkey$

  PBMain=0
End Function

'iRows =  4
'
'26.08.2011;0000123;4.567;0000345;
'25.07.2010;123000;3.14;456;
'24.06.2009;45600;3.14159;0789;
'23.05.2008;123000;19.95;54321;
'
' i            szDatum        iMax          dblPower      iMin
'=============================================================
' 1            26.08.2011     123           4.567         345
' 2            25.07.2010     123000        3.14          456
' 3            24.06.2009     45600         3.14159       789
' 4            23.05.2008     123000        19.95         54321
'
Topic archived. No new replies allowed.