Solved

Separating Each Line in a File

Posted on 2011-03-20
8
310 Views
Last Modified: 2012-05-11
Hello.
I have a file as follows:
name: John
alias: JohnQ2
website: http://johnme.net

I'm trying to seperate each line so it will be:
name: John (in one buffer)
then
alias: JohnQ2 (in another buffer)

here is the code I'm using:
	  char finalsid[1000] = {0};
  char  finalbuff[1000] = {0};
  int p;
	  for(p = 0; p < strlen(mainbuf); p++)
  {

	if(mainbuf[p] == '\n')
	{
		
		strncpy((char*)finalbuff, (const char*)finalsid, strlen(finalsid));
		cout << finalbuff;
		//strncpy((char*)finalsid, "\0", sizeof(finalsid));
		memset(&finalsid,'\0',1000);
		Sleep(2500);
		MessageBox(0, finalbuff, "Output", MB_OK);
		//break;

	}
	else
	{
		strncat((char *)finalsid, (const char*)mainbuf + p, 1);
		//cout << finalsid;
		//Sleep(2500);
	}

Open in new window


Notice I'm using memset to try and clear the "finalsid" buffer so I can rewrite it anew. It does successfully separate each line but I want to store each line in the "finalbuff" buffer. Instead of storing only each line in there, it will mix up the lines like so:
name: John
tp://johnme.net

alias: JohnQ2
//johnme.net

I notice that this only happens AFTER the line
website: http://johnme.net
is loaded. So I'm assuming that memset isn't properly clearing the memory that the largest line has used, and the other lines are just overwriting portions of it.

So basically I need to know how to fully clear "finalsid" so I can write to it anew on every loop.

Thanks!
0
Comment
Question by:JoeD77
  • 5
  • 3
8 Comments
 
LVL 40

Expert Comment

by:evilrix
Comment Utility
Wow, you're making hard work for yourself. If you just want to read all the lines of a text file into memory just use a few standard C++ objects.

http://www.cplusplus.com/reference/stl/vector/
http://www.cplusplus.com/reference/string/string/
http://www.cplusplus.com/reference/iostream/ofstream/
http://www.cplusplus.com/reference/string/getline/
#include <string>
#include <vector>
#include <fstream>

std::string line;
std::vector<std::string> lines
std::ofstream in("somefile.txt");

while(std::getline(in, line))
{
   lines.push_back(line);
}

Open in new window

0
 

Author Comment

by:JoeD77
Comment Utility
Thanks for that but for learning purposes I want to do it using a similar method to the one I posted.
0
 
LVL 40

Expert Comment

by:evilrix
Comment Utility
Heh. Well you can do but what you're learning there is bad practice as far as C++ is concerned.. This is C++ and not C. If you want to learn C++ then what I've posted above is the way this would normally be done. What' you're attempting to do is C programming. Whilst the languages share a common base it is often that case that in C++ you would do thing very different.

Nevertheless, below I've gone through your code and provided some feedback as comments for you to review. See if that helps. If not provide me with the full working code and some example test data and describe clearly what's not working and I'll see what I can do to point you in the right direction.
char finalsid[1000] = {0};
char  finalbuff[1000] = {0};
int p;

// RX: you could use strtok to tokenise rather than rolling your own parser
for(p = 0; p < strlen(mainbuf); p++)  // RX: keep calling strlen here is very inefficiant.
{

   if(mainbuf[p] == '\n')
   {

      strncpy((char*)finalbuff, (const char*)finalsid, strlen(finalsid)); // RX: strncpy doesn't add a null terminator.
      cout << finalbuff;
      //strncpy((char*)finalsid, "\0", sizeof(finalsid));
      
      // RX: this memset is wasteful, since you're using string functions all you need do is set the first char to null (*finalsid = 0);

      memset(&finalsid,'\0',1000); 
      Sleep(2500);
      MessageBox(0, finalbuff, "Output", MB_OK);
      //break;

   }
   else
   {
      strncat((char *)finalsid, (const char*)mainbuf + p, 1);
      //cout << finalsid;
      //Sleep(2500);
   }

Open in new window

0
 

Author Comment

by:JoeD77
Comment Utility
Thanks, evilrix.

I took your advice as best I could:
  int p;
  int sz = strlen(mainbuf);
	  for(p = 0; p < sz; p++)
  {

	if(mainbuf[p] == '\n')
	{
		
		strncpy((char*)finalbuff, (const char*)finalsid, strlen(finalsid));
		cout << finalsid;
		finalsid[0] = '\0';
		strcat(finalsid, "\0");
		Sleep(2500);

	}
	else
	{
		strncat((char *)finalsid, (const char*)mainbuf + p, 1);

	}


  }

Open in new window


with these changes I'm having the same problem. Let me try to explain better.

Okay, the first loop is PERFECT. the lines are read line by line nicely.

_OUTPUT AFTER FIRST LOOP_

name: John
alias: JohnQ2
website: http://johnme.net

_END_

_OUTPUT AFTER SECOND LOOP_

name: Johntp://johnme.net
alias: JohnQ2//johnme.net
website: http://johnme.net

_END_

from what I know about memory, it seems as though once "website: http://johnme.net" is loaded into "finalsid" it's unable to effectively remove them from memory and they are subsequently showing where they shouldn't be.

I hope I made it clear enough and thanks a ton for your assistance.
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 40

Expert Comment

by:evilrix
Comment Utility
I think the issue here is the strncpy. It does not append a null unless the original string is shorter than the length you provide it. You've added code to append a null but you've put it in the wrong place. See my comments in the revised code.

I urge you to look at strtok as it does most of this for you.
http://www.cplusplus.com/reference/clibrary/cstring/strtok/
int p;
  int sz = strlen(mainbuf); // RX: strlen returns a size_t not an int
          for(p = 0; p < sz; p++)
  {

        if(mainbuf[p] == '\n')
        {
                
                strncpy((char*)finalbuff, (const char*)finalsid, strlen(finalsid));
                cout << finalsid; // RX: You need to append the null BEFORE outputing.

                finalsid[0] = '\0'; 
                strcat(finalsid, "\0"); // RX: this line needs to move before the cout
                Sleep(2500);

        }
        else
        {
                strncat((char *)finalsid, (const char*)mainbuf + p, 1);

        }


  }

Open in new window

0
 
LVL 40

Accepted Solution

by:
evilrix earned 500 total points
Comment Utility
I've made the changes I suggested above, to your code, and given my simple test case (I had to make up some test data since you've not provided any) it seems to work.

Please note; however, that this code is horribly inefficient and brittle. If you are using it to learn then fine but please don't consider putting this code into "production".
#include <cstring>
#include <iostream>

using namespace std;

int main()
{
   const char mainbuf[] = "hello\nworld\nand\nit's\nfriends";
   char finalsid[1000] = {0};
   char finalbuff[1000] = {0};

   size_t len = strlen(mainbuf);

   for(size_t idx = 0; idx < len; idx++)
   {

      if(mainbuf[idx] == '\n')
      {

         strncpy((char*)finalbuff, (const char*)finalsid, strlen(finalsid));
         strcat(finalsid, "\0");
         cout << finalsid << endl;

         finalsid[0] = '\0'; 
         // Sleep(2500);

      }
      else
      {
         strncat((char *)finalsid, (const char*)mainbuf + idx, 1);

      }
   }
}

Open in new window

0
 

Author Comment

by:JoeD77
Comment Utility
Excellent. Strtok worked wonders.

Thanks for all your help.
0
 
LVL 40

Expert Comment

by:evilrix
Comment Utility
>> Strtok worked wonders.

Hahaha... I'd just finished a strtok example for you. I'll still post it in case you find it useful. Amazing how much shorter the code is eh? If you could performance profile it I'd be prepared to bet real money it'd be much faster too :

Best of luck.

-Rx.
#include <cstring>
#include <iostream>

using namespace std;

int main()
{
   char mainbuf[] = "hello\nworld\nand\nit's\nfriends";
   char finalbuff[1000] = {0};

   char *p = strtok(mainbuf, "\n");
   while(p)
   {
         strcpy(finalbuff, p);
         cout << finalbuff << endl;
         p = strtok(0, "\n");
   }
}

Open in new window

0

Featured Post

Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

IntroductionThis article is the second in a three part article series on the Visual Studio 2008 Debugger.  It provides tips in setting and using breakpoints. If not familiar with this debugger, you can find a basic introduction in the EE article loc…
Preface I don't like visual development tools that are supposed to write a program for me. Even if it is Xcode and I can use Interface Builder. Yes, it is a perfect tool and has helped me a lot, mainly, in the beginning, when my programs were small…
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use for-loops in the C programming language.
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

8 Experts available now in Live!

Get 1:1 Help Now