char array and pointer C++ - c++

This is my program. The output for char s3[2] = "q" is "QC++" when it should just be "Q". I guess I have to reset the pointer, but i'm not sure how.
void myToUpperCase(const char *source, char *dest){
for(int i = 0; *(source + i) != '\0'; i++)
{
*(dest + i) = toupper(*(source + i));
}
}
char s2[20] = "#c++";
char s3[2] = "q";
char result[20];
myToUpperCase(s2, result);
cout << "- s2 (\"" << s2 << "\") myToUpper() -> " << result << " => " << ((strcmp(result, "#C++") == 0) ? "correct.\n" : "INCORRECT.\n");
myToUpperCase(s3, result);
cout << "- s3 (\"" << s3 << "\") myToUpper() -> " << result << " => " << ((strcmp(result, "Q") == 0) ? "correct.\n" : "INCORRECT.\n");

When you transform your array, you terminate your loop at terminating null which doesn't get copied and so when you print your transformed string, it keeps on printing the content of the memory until first random 0 it encounters. This is why you get garbage. Try this for a change:
#include <iostream>
#include <cctype>
#include <cstring>
void myToUpperCase(const char *source, char *dest)
{
while ((*dest++ = std::toupper(static_cast<unsigned char>(*source++))) != '\0');
}
int main()
{
char s2[20] = "#c++";
char s3[2] = "q";
char result[20];
myToUpperCase(s2, result);
std::cout << "- s2 (\"" << s2 << "\") myToUpper() -> " << result << " => " << ((std::strcmp(result, "#C++") == 0) ? "correct.\n" : "INCORRECT.\n");
myToUpperCase(s3, result);
std::cout << "- s3 (\"" << s3 << "\") myToUpper() -> " << result << " => " << ((std::strcmp(result, "Q") == 0) ? "correct.\n" : "INCORRECT.\n");
}
https://ideone.com/lj1HC5
- s2 ("#c++") myToUpper() -> #C++ => correct.
- s3 ("q") myToUpper() -> Q => correct.
The while loop terminates when it gets to '\0' only this time terminating null is copied already.

You could call memset before calling myToUpperCase to prepare your buffer. That's often helpful.
void * memset ( void * ptr, int value, size_t num );
So...
memset(result, 0, 20);

you should make it so your function returns a pointer to the string, and create the pointer dest in the function and return it, like this you have a situation:
the first call of the function finishes, dest is "#C++", then calls it again and just replaces the # with Q

Related

segfault variable creation c++

So I'm having some troubles with a segfault right now.
The problem appears to be on line 122
file_stream.read(binaryData, fileSizeInt);
The message seems to be unable to create variable object.
I'm using the debugger on CLion, if this is of any help.
I'm fairly new to C++ so please bear with me on this. I've included my source code below, since I have no idea what will and wont be relevant.
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;
//string dataLocation = "/dev/rdisk2"; // Variable for the mounting point of the SD Card.
string dataLocation = "/Volumes/Untitled/data/smith_data_backup.dat"; // Test location
int sectorSize = 512;
int bytesRead = 0;
string outDir = "/Volumes/Untitled/data/readData/";
char data_stop[10] = "Data_Stop";
char* findHeader(char* inputData) {
int i = 1;
//look for the end of the header
while(true) {
//cout << data[i] << '\n';
if (inputData[i] == '}') {
// found the end of the header
cout << "found the end of the header" << '\n';
break;
}
if (i > 200) { // don't get into an infinite loop here
cout << "something went wrong here" << '\n';
break;
}
i++;
}
// copy the header to a new char array
char* header = new char[i+1];
memcpy(header, &inputData[0], (size_t) (i +1));
return header;
}
int main() {
ifstream file_stream;
file_stream.open(dataLocation);
for( int j = 0; j < 10; j++ ) {
char data[sectorSize]; // figure out a decent size for this.....
string date = "";
string time = "";
string site = "";
string intId = "";
string totalFiles = "";
string fileNo = "";
string fileSize = "";
try {
// read the data file... this will be fun
cout << "Reading the data file" << '\n';
file_stream.read(data, sectorSize);
bytesRead += sectorSize;
if (data[0] == '{') {
char *header = findHeader(data);
cout << header << '\n';
//loop over the header to find the date, time, site ID, Instrument ID, and expected file size.
int commasFound = 0;
for(int i = 1; header[i] != '}', i++;) {
// increment the number of commas that have been found
if (header[i] == ',') {
commasFound ++;
continue;
}
//check for the end f the header
if (header[i] == '}') {
break;
}
//for some reason the first one never gets added
if (i==2) {
date += header[1];
}
// append to appropriate strings based on the number of commas that have been passed in the header
if (commasFound == 0) {
date += header[i];
}
if (commasFound == 1 && time.length() < 6) {
time += header[i];
}
if (commasFound == 2) {
fileNo += header[i];
}
if (commasFound == 6) {
site += header[i];
}
if (commasFound == 8) {
intId += header[i];
}
if (commasFound == 16) {
fileSize += header[i];
}
if (commasFound == 17) {
totalFiles += header[i];
}
//paranoia of infinite loops
if (i > 150) {
break;
}
}
string formattedDate = "20" + date.substr(4,2) + date.substr(2,2) + date.substr(0,2);
cout << formattedDate << " " << time << " " << " " << site << " " << intId << " " << fileSize << " " << totalFiles<< " " << '\n';
// Read in the data size
int fileSizeInt = atoi(fileSize.c_str()) * atoi(fileSize.c_str());
char binaryData[fileSizeInt];
file_stream.read(binaryData, fileSizeInt);
bytesRead += fileSizeInt;
string dateDir = outDir + formattedDate.substr(0,4) + "/" + date.substr(2,2) + "/" + site + "/" + date.substr(0,2) + "/";
string fileName = dateDir + formattedDate + "_" + time + "_" + site + "_" + intId + "_Full_Data.dat";
//cout << fileName << '\n';
//create the directory with the date.
string mkdirCommand = "mkdir -p " + dateDir;
system(mkdirCommand.c_str());
cout << "size " << sizeof(binaryData) << '\n';
//write data to file
try {
cout << "Write the data file " << '\n';
cout << header << " " << strlen(header) << '\n';
ofstream outFile;
outFile.open(fileName.c_str());
outFile.write(header, strlen(header));
outFile.write(binaryData, sizeof(binaryData));
outFile.write(data_stop, sizeof(data_stop));
outFile.close();
} catch (ofstream::failure e ) {
cout << "Unable to write the file " << fileName << '\n';
}
//read till the start of the next sector
int nextSector = (int) ceil(((double) bytesRead)/512.0);
int startOfNextSector = nextSector * 512;
cout << startOfNextSector << '\n';
int bytesToRead = startOfNextSector - bytesRead;
char dump[bytesToRead];
file_stream.read(dump, bytesToRead);
bytesRead += bytesToRead;
// The first block may be empty, quick check to see if the first block needs to be skipped
} else if (j == 0 && data[0] != '{') {
cout << "Skipping the first block" << '\n';
continue;
} else {
//cout << "no start here....." << bytesRead << '\n';
}
}
catch (ifstream::failure& e) {
cout << "Error" << "\n";
break;
}
}
file_stream.close();
return 0;
}

Remove substring that contains certain pattern and ends with specific char

For example I have a string like following:
"VISITOR_INFO1_LIVE=USv90B-7CzI; LOGIN_INFO=e486e37a395be3f0e3b3237d090a6829c1oAAAB7IjQiOiAiREVMRUdBVEVEIiwgIjciOiAwLCAiMSI6IDEsICIzIjogMjAxMTk0MTMwNiwgIjgiOiA2MDgwMTg0NTEzNjQsICIxMCI6IDIzOTYyMTEyODczNH0=; PREF=f5=30;HSID=AHuJQBOVR0lQoRt_3; APISID=QaParXGsQcEPCzKg/A1smCfYrfMjxvfEPT; YSC=Vm3Amq5loFM";
I want to remove all the patterns that contains *SID (HSID,APISID here) upto ';'. I also want to remove substring "LOGIN_INFO= ....;"
So, output string should be "VISITOR_INFO1_LIVE=L80EDuHCEF8; PREF=f5=30";
Following is the solution I have come up with but I think performance can be improved:
const char *str ="VISITOR_INFO1_LIVE=USv90B-7CzI; LOGIN_INFO=e486e37a395be3f0e3b3237d090a6829c1oAAAB7IjQiOiAiREVMRUdBVEVEIiwgIjciOiAwLCAiMSI6IDEsICIzIjogMjAxMTk0MTMwNiwgIjgiOiA2MDgwMTg0NTEzNjQsICIxMCI6IDIzOTYyMTEyODczNH0=; PREF=f5=30;HSID=AHuJQBOVR0lQoRt_3; APISID=QaParXGsQcEPCzKg/A1smCfYrfMjxvfEPT; YSC=Vm3Amq5loFM";
char *Cookie = NULL;
cout << "original string is:\n" << str << "\n";
int len = strlen(str)+1;
cout << "length of original string is : " << len << "\n";
Cookie = new char[strlen(str)];
strncpy(Cookie,str,len);
char *p1 = strstr(Cookie,"LOGIN_INFO");
char *p2 = NULL;
if(p1){
p2 = strstr(p1,";")+1;
while(*p2 == ' ') p2++;
}
if(p1 && p2)
memmove(p1,p2,strlen(p2)+1);
char *ID = strstr(Cookie,"SID");
while( ID != NULL){
char *start_pos = NULL, *end_pos = NULL;
while((*ID != ';') && (*ID != Cookie[0]) && (*ID != ' ')){
--ID;
}
if(*ID == Cookie[0]) start_pos = ID;
else start_pos = ID+1;
end_pos = strstr(start_pos,";")+1;
while(*end_pos == ' ')
end_pos++;
memmove(start_pos,end_pos,strlen(end_pos)+1);
// }
/*else
std::cout << "does not find substr " << "\n";*/
// cout << "modified string is :" << Cookie << "\n";
ID = strstr(Cookie,"SID");
}
//cout << "final modified string is : " << Cookie << "\n";
char *Cookie_modified = NULL;
const char *pch = strstr(Cookie,"PREF");
if(pch != NULL){
const char *append = "&f2=8000000";
int len = strlen(Cookie) + strlen(append) + 1;
Cookie_modified = new char[len];
strncpy(Cookie_modified,Cookie,len);
Cookie_modified[len-1] = '\0';
char *p = strstr(Cookie_modified,"PREF");
strncpy(p+(strlen(p)),append,strlen(append));
cout << "modified Cookie is : " << Cookie_modified << "\n";
// cout << "length of modified cookie is : " << strlen(Cookie_modified) << "\n";
}
else{
cout << "do not find reference: " << "\n";
const char *append = ";PERF=f2=8000000";
int len = strlen(Cookie) + strlen(append) + 1;
Cookie_modified = new char[len];
Cookie_modified[len-1] = '\0';
strcat(Cookie_modified,Cookie);
strcat(Cookie_modified,append);
cout << "case 2: modified Cookie is: " << Cookie_modified << "\n";
}
delete[] Cookie;
delete[] Cookie_modified;
return 0;
}
Just use std::regex_replace with the following regex:
([^\s]*SID[^;]*;|[^\s]*LOGIN_INFO[^;]*;)
And replace with empty string.
Live Demo

swap multiple objects in char array with one another at the same time

I'm trying to make a program using a c-string (no std:string allowed for this one) in which the contents of the c-string are a name formatted : lastName, firstName middleName or as the program will treat it lastName, firstMiddleName.
What I want to do is simply switch the format to firstMiddleName lastName.
I'm wondering if there's some elegant way to do so by possibly using an index to find the comma in order separate the two parts of the c-string, and then just something similar to str.substr(0, index) in order to swap the two around easily. Is this possible at all? I feel like I've exhausted every thread on the matter
any help is greatly appreciated
I think it is better to create struct for person with last name and first name.
typedef struct {
char* firstname;
char* lastname;
} person_t;
To split string by some separator you can use strtok function like this
char* last = strtok(str, ",");
where str is the source string and , is separator.
Now you need to create an instance of the person_t and copy values
person_t create_person(char* firstname, char* lastname) {
person_t person;
int length;
length = strlen(firstname);
person.firstname = malloc(sizeof(char) * (length + 1));
person.firstname[length] = '\0';
length = strlen(lastname);
person.lastname = malloc(sizeof(char) * (length + 1));
person.lastname[length] = '\0';
strcpy(person.firstname, firstname);
strcpy(person.lastname, lastname);
return person;
}
Now you can output these values as you want. See full code below
#include <stdio.h>
#include <string.h>
typedef struct {
char* firstname;
char* lastname;
} person_t;
person_t create_person(char* firstname, char* lastname) {
person_t person;
int length;
length = strlen(firstname);
person.firstname = malloc(sizeof(char) * (length + 1));
person.firstname[length] = '\0';
length = strlen(lastname);
person.lastname = malloc(sizeof(char) * (length + 1));
person.lastname[length] = '\0';
strcpy(person.firstname, firstname);
strcpy(person.lastname, lastname);
return person;
}
int main(void) {
char str[] = "Surname, Firstname Middlename";
char* last = strtok(str, ",");
char* first = strtok(NULL, ",") + 1;
person_t person = create_person(first, last);
printf("firstname: %s\nlastname: %s\n", person.firstname, person.lastname);
return 0;
}
The output of the above code is
firstname: Firstname Middlename
lastname: Surname
Also don't forget to clean up ;)
void remove_person(person_t person) {
free(person.firstname);
free(person.lastname);
}
You have tagged this question for C++.
Here I present two versions.
t266a() conforms to c++ and streams, but uses only c-string (no std::string)
t266b() conforms to c++ and streams, and uses std::string (no c-string)
I intentionally used blank space to align sections of the code-with-c-strings to the code-with-std::strings, but you will need to load this into a capable editor to show them side by side.
// 1 & 2 of 3 c++ includes
#include <iostream> // cout, cin, istream
#include <algorithm> // std::fill
// removed: include <cstring> - not needed
// forward
// c++, but limited to c-string, no std::string
int t266a(std::istream& ss);
// c++, using std::string
int t266b(std::istream& ss);
const int MAX_BUFF = (1024*1024); // for c-string, how big should this be?
// default stack size ubuntu 15.10 (64) is 8MB, so plenty of room
// ///////////////////////////////////////////////////////////////////////
size_t getLine (std::istream& ss, char* buff, size_t& buffLen)
{
size_t karCount = 0;
for (size_t i=0; i<MAX_BUFF; ++i) // limit read to MAX_BUFF chars
{
char kar = 0;
ss.read(&kar, 1); // binary stream read, 1 char at a time
if (ss.eof()) break;
if(ss.bad()) { // either fail or bad
std::cerr << "stream bad x " << std::endl;
break;
}
buff[i] = kar; // capture kar to buff
karCount += 1; // count kar's
if ('\n' == buff[i]) // end-of-line within stream
{
buffLen = i;
buff[i] = 0; // null-terminate in buff
break; // line complete
}
}
return(karCount);
}
// ///////////////////////////////////////////////////////////////////////
size_t buffFind(const char* buff, size_t buffLen, const char kar)
{
size_t commaAt = buffLen + 1; // not found
for (size_t i=0; i<buffLen; ++i)
{
if(kar == buff[i])
{
commaAt = i; // found comma
break;
}
}
return (commaAt);
}
// ///////////////////////////////////////////////////////////////////////
// c++, but limited to c-string, no std::string
int t266a(std::istream& ss)
{
std::cout << "t266a() C++, but limited to c-string, no std::string" << std::endl;
std::cout << "MAX_BUFF: " << MAX_BUFF << std::endl;
char buff[MAX_BUFF];
size_t buffCount = 0;
size_t buffLen = 0;
do
{
// buff[0] = '\0'; // a c-string terminates with the 1st 0 ... need to clear all?
// (void)::memset(buff, 0, MAX_BUFF); // from <cstring> lib. clear all c-style
std::fill(buff, buff+MAX_BUFF, '\0'); // from <algorithm> lib. clear all c++style
(void)getLine(ss, buff, buffLen); // local function
if(ss.eof()) break;
if(ss.bad()) { // either fail or bad
std::cerr << " " << ss.good()
<< " " << ss.eof()
<< " " << ss.fail()
<< " " << ss.bad()
<< std::endl;
break;
}
buffCount += 1;
if (ss.eof()) break;
//std::cout << " Input: " << buffCount << " (" << buffLen << ") '" << buff << "'" << std::endl;
// find comma
size_t commaAt = buffFind(buff, buffLen, ',');
if(commaAt > buffLen)
{
std::cerr << " Err: invalid input: no comma on line "<< std::endl;
break;
}
if(commaAt < 1)
{
std::cerr << " Err: invalid input: comma at beginning of line "<< std::endl;
break;
}
buff[commaAt] = 0; // take advantage of c-string
std::cout << " Output: "
<< &buff[commaAt+1] // Firstname Middlename [(where comma was) .. (end of buff)]
<< " "
<< &buff[0] // Surname [0..(where comma was)]
<< " (bufLen: " << buffLen << ")" << std::endl;
if (ss.eof()) { break;}
}while (true);
return(0);
} // int t266a(std::istream&)
// ///////////////////////////////////////////////////////////////////////
// 3 of 3 c++ includes
#include <sstream>
// ///////////////////////////////////////////////////////////////////////
// ///////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[] )
{
std::cout << "argc: " << argc << std::endl;
for (int i=0; i<argc; i+=1) std::cout << argv[i] << " ";
std::cout << std::endl;
setlocale(LC_ALL, "");
std::stringstream ssTest;
{
for (int i=1; i<=8; ++i) // 8 entries
{
ssTest << "Surname" << i << ", Firstname" << i << " Middlename" << i << "\n";
}
// add test cases here
// trailing spaces --------------------------------vv
// ssTest << " SurnameX, FirstnameX MiddlenameX \n" ;
// ^--leading spaces
// ssTest << "SnameY, FnameY MnameY\n" ;
// different size names
}
int retVal = 0;
{
std::stringstream ss (ssTest.str()); // load ss
std::cout << "\nistream (input): \n" << ss.str() << std::endl;
retVal += t266a(ss); // run c++ using c-strings
}
{
std::stringstream ss(ssTest.str()); // load ss
std::cout << "\n\nistream (input): \n" << ss.str() << std::endl;
retVal += t266b(ss); // run c++ using std::string
}
std::cout << "\n\nFINI " << std::endl;
return(retVal);
}
// ///////////////////////////////////////////////////////////////////////
// c++, but using std::string (no c-strings)
int t266b(std::istream& ss)
{
std::cout << "t266b() C++, using std::string (no c-strings)" << std::endl;
std::string buff; // buff grows as needed
size_t buffCount = 0; // line count
//size_t buffLen = 0; // now buff.size()
do
{
buff.clear();
(void)std::getline(ss, buff); // uses default delim ('\n')
if(ss.eof()) break;
if(ss.bad()) { // bad or fail bit set
std::cerr << " " << ss.good()
<< " " << ss.eof()
<< " " << ss.fail()
<< " " << ss.bad()
<< std::endl;
break;
}
buffCount += 1;
if (ss.eof()) break;
//std::cout << " Input: " << buffCount << " (" << buff.size() << ") '" << buff << "'" << std::endl;
// find comma
size_t commaAt = buff.find(',');
if(commaAt == std::string::npos)
{
std::cerr << " Err: invalid input: no comma " << std::endl;
break;
}
if(commaAt < 1)
{
std::cerr << " Err: invalid input: comma at beginning of line "<< std::endl;
break;
}
std::cout << " Output: "
<< buff.substr(commaAt+1) // Firstname Middlename [(where comma was) .. (end of buff)]
<< " "
<< buff.substr(0, commaAt) // Surname [0..(where comma was)]
<< " (buff.size(): " << buff.size() << ")" << std::endl;
if (ss.eof()) { break;}
}while (true);
return(0);
} // int t266b(std::istream&)

My vector structure is no iterating as expected

I get no errors, but my output is not what I wanted. I want to get 'stuff + i' to be the input into a vector. BUT my output is just my initial 'stuff' variable - 1 char.
stuff
tuff
uff
ff
f
/0
/0
gello?
ello?
llo?
gello?
Code:
#include <iostream>
#include <string>
#include <vector>
struct Playlist
{
std::string name;
} ;
int main()
{
std::vector<Playlist> playlist;
std::cout << "Input 10 stuff" << std::endl;
for( int i = 0; i < 10; ++i )
{
Playlist ok;
ok.name = "stuff " + i;
playlist.push_back( ok );
std::cout << playlist.size() << std::endl;
}
std::vector<Playlist>::iterator iter = playlist.begin();
while( iter != playlist.end() )
{
std::cout << iter->name << std::endl;
++iter;
}
std::cout << "gello?" << std::endl;
std::vector::iterator iter = playlist.begin();
while( iter != playlist.end() ) { std::cout << iter->name << std::endl; ++iter; }
std::cout << "gello?" << std::endl;
return 0;
}
Change this statement
ok.name = "stuff " + i;
to
ok.name = "stuff " + std::to_string( i );
As for statement
ok.name = "stuff " + i;
then in the right side there is used the pointer arithmetic. The string literal is converted to pointer to its first element. So
"stuff " + 0 returns pointer to character 's'
"stuff " + 1 returns pointer to character 't'
"stuff " + 1 returns pointer to character 'u'
and so on.
So the first push_back deals with string "stuff ". The second - with string "tuff ", the third - with string "uff " and so on.
As result the program has undefined behaviour because sizeof( "stuff " ) is less than 10 and you are trying to access memory beyond the string literal.

C++ Parsing a line out of a large file

I have read an entire file into a string from a memory mapped file Win API
CreateFile( "WarandPeace.txt", GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 )
etc...
Each line is terminated with a CRLF. I need to find something on a line like "Spam" in the line "I love Spam and Eggs" (and return the entire line (without the CRLF) in a string (or a pointer to the location in the string) The original string cannot be altered.
EDITED:
Something like this:
string ParseStr( string sIn, string sDelim, int nField )
{
int match, LenStr, LenDelim, ePos, sPos(0), count(0);
string sRet;
LenDelim = sDelim.length();
LenStr = sIn.length();
if( LenStr < 1 || LenDelim < 1 ) return ""; // Empty String
if( nField < 1 ) return "";
//=========== cout << "LenDelim=" << LenDelim << ", sIn.length=" << sIn.length() << endl;
for( ePos=0; ePos < LenStr; ePos++ ) // iterate through the string
{ // cout << "sPos=" << sPos << ", LenStr=" << LenStr << ", ePos=" << ePos << ", sIn[ePos]=" << sIn[ePos] << endl;
match = 1; // default = match found
for( int k=0; k < LenDelim; k++ ) // Byte value
{
if( ePos+k > LenStr ) // end of the string
break;
else if( sIn[ePos+k] != sDelim[k] ){ // match failed
match = 0; break; }
}
//===========
if( match || (ePos == LenStr-1) ) // process line
{
if( !match ) ePos = LenStr + LenDelim; // (ePos == LenStr-1)
count++; // cout << "sPos=" << sPos << ", ePos=" << ePos << " >" << sIn.substr(sPos, ePos-sPos) << endl;
if( count == nField ){ sRet = sIn.substr(sPos, ePos-sPos); break; }
ePos = ePos+LenDelim-1; // jump over Delim
sPos = ePos+1; // Begin after Delim
} // cout << "Final ePos=" << ePos << ", count=" << count << ", LenStr=" << LenStr << endl;
}// next
return sRet;
}
If you like it, vote it up. If not, let's see what you got.
If you are trying to match a more complex pattern then you can always fall back to boost's regex lib.
See: http://www.boost.org/doc/libs/1_41_0/libs/regex/doc/html/index.html
#include <iostream>
#include <string>
#include <boost/regex.hpp>
using namespace std;
int main( )
{
std::string s;
std::string sre("Spam");
boost::regex re;
ifstream in("main.cpp");
if (!in.is_open()) return 1;
string line;
while (getline(in,line))
{
try
{
// Set up the regular expression for case-insensitivity
re.assign(sre, boost::regex_constants::icase);
}
catch (boost::regex_error& e)
{
cout << sre << " is not a valid regular expression: \""
<< e.what() << "\"" << endl;
continue;
}
if (boost::regex_match(line, re))
{
cout << re << " matches " << line << endl;
}
}
}
Do you really have to do it in C++? Perhaps you could use a language which is more appropriate for text processing, like Perl, and apply a regular expression.
Anyway, if doing it in C++, a loop over Prev_delim_position = sIn.find(sDelim, Prev_delim_position) looks like a fine way to do it.
system("grep ....");

Resources