I have one array of WCHAR is like this
WCHAR Path[256];
So I'm passing this array in my function getpath(Path) and It's filling the value in path like this:
//device/systemName/
So I want to get only device from above string.
My code is here:
WCHAR *pDevName;
int i = 0;
int j = 0;
while(Path[i] != NULL){
if(0 ==(wcscmp(Path, L"/")))
{
//i = i + 2;
++i;
continue;
}
else
{
pDevName[j] = Path[i];
++i;
++j;
if (0 == wcscmp(Path, L"/")){
break;
}
}
My code is getting compiled but it's not returning for me device from WCHAR array. It's returning //devicename/systemName/, which is coming from pDevName.
I have doubt over my comparison on wcscmp(). So my question is how to compare / with remaining wchar array value.
wcscmp compares a string, not a character. You're also passing the same address to wcscmp every time - Path, which means all you're doing is comparing the whole string against "/", which will always fail.
If you want to test a single character you can simply compare its value directly, for example:
WCHAR *pDevName;
// NB: I assume you are allocating pDevName and just left that out of the code
// for brevity.
int i = 0;
int j = 0;
while(Path[i] != L'\0'){
if(Path[i] == L'/')
{
++i;
continue;
}
else
{
// NB: you should check for overflow of pDevName here
pDevName[j++] = Path[i++];
if (Path[i] == L'/')
break;
}
}
Since you specified c++, it would be easier to do something like this:
#include <string>
using namespace std;
wstring get_device_name(const wchar_t* path)
{
wstring source(path);
wstring device_name;
if (source.substr(0, 2)==L"//")
{
size_t position= source.find(L'/', 2);
if (position==wstring::npos)
device_name= source.substr(2);
else
device_name= source.substr(2, position-2);
}
return device_name;
}
Related
for part of a school lab I need to read in unique words and their corresponding count with a struct. I am new to structs so please bear with me. I am getting an access violation when I try to write the adress of the current word to the character pointer inside of the current instance of my struct. I have read that this is due to dereferencing a nullptr. I have tried to understand this, but I just don't get it. I have resized arrays just like this on regular char** arrays for accepting new words. I am at a loss, any help would be greatly appreciated. The input file used here is just random words separated by non letter characters but not - or , Here is my code:
#define _CRT_SECURE_NO_WARNINGS
#define _CRTDBG_MAP_ALLOC
#include <iostream>
#include <iomanip>
#include <fstream>
#include <limits>
using std::cin;
using std::cout;
using std::endl;
using std::setw;
using std::right;
using std::left;
using std::ifstream;
using std::ofstream;
const int BUFFER = 100; //I figure this buffer is big enough for any given word
struct Word_Count_STRUCT
{
char* WORD = nullptr;
int COUNT = 0;
};
int main()
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
//Input for phrase
ifstream iphrase;
//Output to CSV (word count)
ofstream o_count;
//Word Exceptions
ifstream xinWord;
char wordbuffer[BUFFER] = { '\0' };
char ch = 0;
Word_Count_STRUCT** uniquewords = nullptr;
Word_Count_STRUCT** temp = nullptr;
int k = 0;
int wordcount = 0;
char* cword = nullptr; //Current Word
bool NextWord_flag = false;
bool interwordpunct = false;
bool NewWord_flag = true;
iphrase.open("C:\\Users\\me\\Desktop\\henroE.txt");
if (iphrase.is_open())
{
while (!iphrase.eof())
{
iphrase.get(ch);
if (isalpha(ch) || ch == '\'' || ch == '-')
{
wordbuffer[k] = ch;
++k;
NextWord_flag = true;
if (ch == '\'' || ch == '-')
interwordpunct = true;
}
if ( (NextWord_flag == true) && (!isalpha(ch)) && (interwordpunct == false) )
{
k = 0;
cword = new char[strlen(wordbuffer) + 1];
strcpy(cword, wordbuffer);
memset(wordbuffer, '\0', sizeof(wordbuffer));
for (int i = 0; (i < wordcount) && (NewWord_flag == true); ++i)
{
int cmp = _stricmp(uniquewords[i]->WORD, cword);
if (cmp == 0)
{
NewWord_flag = false;
uniquewords[i]->COUNT++;
delete[] cword;
}
}
if (NewWord_flag == true)
{
temp = new Word_Count_STRUCT * [wordcount + 1]();
for (int i = 0; i < wordcount; ++i)
{
temp[i] = uniquewords[i];
}
delete[] uniquewords;
temp[wordcount]->WORD = cword;
temp[wordcount]->COUNT++;
uniquewords = temp;
++wordcount;
NextWord_flag = false;
}
interwordpunct = false;
NewWord_flag = true;
}
}
}
I get an error on this line:
temp[wordcount]->WORD = cword;
I also get an error on the int value COUNT as well if I comment the line above it out. So I am guessing it is something with how I initialized the struct.
Worth noting that if I do not initialize this call:
temp = new Word_Count_STRUCT * [wordcount + 1]();
and instead just leave it as
temp = new Word_Count_STRUCT * [wordcount + 1];
I get another access violation but for reading instead of writing at 0xFFFFF...
At a loss, thank you for any help :)
You've got a number of things wrong. First, using fixed-length character buffers instead of C++ strings is about 20 years out of date and WILL cause buffer overflow errors unless you are exceedingly careful.
But this is an issue:
temp = new Word_Count_STRUCT * [wordcount + 1]();
for (int i = 0; i < wordcount; ++i)
{
temp[i] = uniquewords[i];
}
delete[] uniquewords;
But where did you allocate uniquewords? You declared it.
You also allocate cword outside a loop but the delete it inside a loop -- which seems really fishy, too.
But note that all you've allocated are pointers. I don't see you actually allocating the structure you're trying to put data in.
I have made a <stdio.h> only strcmp equivalent... "ish"
But i WOULD like to know. Is there something i've skipped and/or should fix, if i decide to use this as a substitute for strcmp?
DISCLAIMER:: I have no intend to actually substitute strcmp from my daily usage, but I would like to know if I'm currently able to create a similar substitute for it.
code for it:
#include <stdio.h>
// #include <ctype.h> // Optional
typedef char string[20];
int stringcmp(string str1, string str2);
int strcount(string str);
int main (void)
{
string cmp1, cmp2;
printf("cmp1: ");
scanf("%s", cmp1);
printf("cmp2: ");
scanf("%s", cmp2);
// If you want the function to be ran Case-Insensitive, [ctype] library might be your friend
int result = stringcmp(cmp1, cmp2);
printf("(%i)\n", result);
return result;
}
int strcount(string str)
{
int i = 0;
while(str[i] != '\0')
{
i++;
}
return i;
}
int stringcmp(string str1, string str2)
{
int imax = strcount(str1);
if (imax < strcount(str2))
{
imax = strcount(str2);
}
for (int i = 0; i < imax; i++)
{
if (str1[i] < str2[i])
{
return 1;
}
else if (str1[i] > str2[i])
{
return 2;
}
}
return 0;
}
the function in topic makes usage of another one, by the way. Is that a problem in any way?
For starters the function declaration is incorrect.
In fact your function declaration after adjusting the parameters by the compiler looks like
int stringcmp( char *str1, char *str2);
while the declaration of the standard function strcmp looks like
int strcmp(const char *str1, const char *str2);
That is the function deals with pointers to constant strings because within the function passed strings are not changed.
To compare two strings there is no any need to calculate their lengths. It is just inefficient. Moreover you shall use the type size_t instead of the type int to store a length of a string because an object of the type int can be not large enough to store values of lengths of strings.
Also there is an explicit bug in your approach
if (str1[i] < str2[i])
{
return 1;
}
else if (str1[i] > str2[i])
{
return 2;
}
because you are returning a positive value ( 1 ) when the first string is less than the second string while the standard C function strcmp returns a negative value in this case. and vice versa when the first string is greater than the second string you are returning again a positive value ( 2 ).
From the C Standard (7.23.4.2 The strcmp function)
3 The strcmp function returns an integer greater than, equal to,
or less than zero, accordingly as the string pointed to by s1 is
greater than, equal to, or less than the string pointed to by s2.
And moreover the elements of strings shall be compared as objects of the type unsigned char.
Consider the following demonstrative program.
#include <stdio.h>
#include <string.h>
#include <limits.h>
int main(void)
{
char s1[] = { CHAR_MIN, '\0' };
char s2[] = { CHAR_MAX, '\0' };
printf( "s1 is greater than s2 is %s\n", 0 < strcmp( s1, s2 ) ? "true" : "false" );
return 0;
}
Its output is
s1 is greater than s2 is true
In fact the arrays are declared like
char s1[] = { -128, '\0' };
char s2[] = { 127, '\0' };
provided that the type char behaves as the type signed char (that is usually the default behavior of the type char for many compilers).
So if the elements of the arrays will be compared as objects of the type char then you will get an opposite result to the result of the standard C function strcmp.
The function can be much simpler defined for example the following way
int stringcmp( const char *str1, const char *str2 )
{
while ( *str1 && *str1 == *str2 )
{
++str1;
++str2;
}
return ( unsigned char )*str1 - ( unsigned char )*str2;
}
As you can see there is no any need to calculate preliminary lengths of the strings.
It seems like it would work, although strcmp does not return 0, 1, and 2, but 0, <0, and >0.
See https://www.cplusplus.com/reference/cstring/strcmp/ for reference.
By the way, why not use string.c_str()?
strcmp(string str1,string str2) will:
return an a number less than zero if str1 < str2
return zero if str1 == str2
return an a number more than zero if str1 > str2
so your function should imitate this behavior
int stringcmp(string str1, string str2)
{
int imax = strcount(str1);
if (imax < strcount(str2))
{
imax = strcount(str2);
}
for (int i = 0; i < imax; i++)
{
if (str1[i] == 0 && str2[i] == 0) return 0;
if (str1[i] == 0) return 1;
if (str2[i] == 0) return -1;
if (str1[i] < str2[i])
{
return -1;
}
else if (str1[i] > str2[i])
{
return 1;
}
}
return 0;
}
#include<stdio.h>
#include<string.h>
int main(){
printf("%d",strcmp("hell ","hell"));
}
bro scanf dosent scan white spaces but if you run the above code white spaces play an important role it prints 1;
so check alternative
I want to parse relatively simple registry file format, let's assume it's plain ascii, saved in old REGEDIT4 format. I want to parse it using standard c++ regex class or function (preferably no boost). As an input data it could take for example sample file like this:
REGEDIT4
[HKEY_LOCAL_MACHINE\SOFTWARE\MyCompany\ConfigurationData\v1.0]
[HKEY_LOCAL_MACHINE\SOFTWARE\MyCompany\ConfigurationData\v1.0\General]
"SettingDword"=dword:00000009
"Setting1"="Some string 1"
"SettingString2"="my String"
[HKEY_LOCAL_MACHINE\SOFTWARE\MyCompany\ConfigurationData\v1.0\Networking]
"SettingDword2"=dword:00000002
"Setting2"="Some string 2"
"SettingString3"="my String2"
What I have briefly analyzed - scanning multiple [] can be done using for example cregex_token_iterator class, but main problem is that it is working in opposite way, which I want to use it. I want to start matching pattern like this: regex re("(\\[.*?\\])"), but token iterator returns all strings, which were not matched, which does sounds kind silly to me.
Basically I would like to match first whole section (\\[.*?\\])(.*?\n\n), and then pick up registry path first, and key-values next - then split using regex key-value pairs.
It's really incredible that in C# it's relatively easy to write regex matcher like this, but I would prefer go with C++, as it's native, does not have performance and assembly unload problems.
Finally cross analyzed - it's possible to use regex_search, but search needs to be retried by continuing from next char* after found pattern.
Below is almost complete example to load .reg file at run-time, I'm using MFC's CString, because it's slightly easier to use than std::string and portability is not needed currently.
#include "stdafx.h"
#include <afx.h> //CFile
#include "TestRegex.h"
#include <fstream>
#include <string>
#include <regex>
#include <map>
CWinApp theApp;
using namespace std;
typedef enum
{
eREG_DWORD = REG_DWORD,
eREG_QWORD = REG_QWORD,
eREG_BINARY = REG_BINARY,
eREG_SZ = REG_SZ
}eRegType;
class RegVariant
{
public:
eRegType type;
union
{
DWORD dw;
__int64 qw;
};
CStringA str;
};
class RegKeyNode
{
public:
// Paths to next nodes
map<CStringA, RegKeyNode> keyToNode;
// Values of current key
map<CStringA, RegVariant> keyValues;
};
map<HKEY, RegKeyNode> g_registry;
int char2int(char input)
{
if (input >= '0' && input <= '9')
return input - '0';
if (input >= 'A' && input <= 'F')
return input - 'A' + 10;
if (input >= 'a' && input <= 'f')
return input - 'a' + 10;
return 0;
}
void hexToBin( const char* hex, CStringA& bin, int maxSize = -1 )
{
int size = (strlen(hex) + 1)/ 3;
if(maxSize != -1 && size > maxSize)
size = maxSize;
unsigned char* buf = (unsigned char*)bin.GetBuffer(size);
for( int i = 0; i < size; i++ )
buf[i] = char2int( hex[ i*3 ] ) * 16 + char2int(hex[i * 3 + 1]);
bin.ReleaseBuffer();
}
int main()
{
HMODULE hModule = ::GetModuleHandle(nullptr);
AfxWinInit(hModule, nullptr, ::GetCommandLine(), 0);
//
// Load .reg file.
//
CString fileName = L"test1.reg";
CStringA file;
CFile cfile;
if (cfile.Open(fileName, CFile::modeRead | CFile::shareDenyNone))
{
int len = (int)cfile.GetLength();
cfile.Read(file.GetBuffer(len), len);
file.ReleaseBuffer();
}
cfile.Close();
file.Replace("\r\n", "\n");
const char* pbuf = file.GetBuffer();
regex reSection("\\[(.*?)\\]([^]*?)\n\n");
regex reLine("^\\s*\"(.*?)\"\\s*=\\s*(.*)$");
regex reTypedValue("^(hex|dword|hex\\(b\\)):(.*)$");
regex reStringValue("^\"(.*)\"$" );
cmatch cmSection, cmLine;
//
// For each section:
//
// [registry path]
// "value1"="value 1"
// "value2"="value 1"
//
while( regex_search(pbuf, pbuf + strlen(pbuf), cmSection, reSection) )
{
CStringA path = cmSection[1].str().c_str();
string key_values = cmSection[2].str();
const char* pkv = key_values.c_str();
int iPath = 0;
CStringA hkeyName = path.Tokenize("\\", iPath).MakeUpper();
RegKeyNode* rnode;
if( hkeyName.Compare("HKEY_LOCAL_MACHINE") == 0 )
rnode = &g_registry[HKEY_LOCAL_MACHINE];
else
rnode = &g_registry[HKEY_CURRENT_USER]; // Don't support other HKEY roots.
//
// Locate path where to place values.
//
for( ; hkeyName = path.Tokenize("\\", iPath); )
{
if( hkeyName.IsEmpty() )
break;
rnode = &rnode->keyToNode[hkeyName];
}
//
// Scan "key"="value" pairs.
//
while( regex_search(pkv, pkv+strlen(pkv), cmLine, reLine ))
{
CStringA key = cmLine[1].str().c_str();
string valueType = cmLine[2].str();
smatch cmTypeValue;
RegVariant* rvValue = &rnode->keyValues[key];
//
// Extract type and value.
//
if(regex_search(valueType, cmTypeValue, reTypedValue))
{
string type = cmTypeValue[1].str();
string value = cmTypeValue[2].str();
if( type == "dword")
{
rvValue->type = eREG_DWORD;
rvValue->dw = (DWORD)strtoul(value.c_str(), 0, 16);
}
else if (type == "hex(b)")
{
rvValue->type = eREG_QWORD;
rvValue->qw = 0;
if( value.size() == 8 * 2 + 7 )
{
CStringA v;
hexToBin(value.c_str(), v, sizeof(__int64));
rvValue->qw = *((__int64*)v.GetBuffer());
}
} else //if (type == "hex")
{
rvValue->type = eREG_BINARY;
hexToBin(value.c_str(), rvValue->str);
}
} else if( regex_search(valueType, cmTypeValue, reStringValue))
{
rvValue->type = eREG_SZ;
rvValue->str = cmTypeValue[1].str().c_str();
}
pkv = cmLine[2].second;
} //while
pbuf = cmSection[2].second;
} //while
return 0;
}
I am trying to find a string which is inside 2D char array and return it's index. For example:
char idTable[255][32];
char tester[] = { 't','e','s','t','e','r','\0' };
memcpy(idTable[43], tester, 7);
uint8_t id = getID(name[0]);
//name is returned from function "char **name = func();"
//but I have the same results when I try using normal char array...
I've had partial success with the first part of the below code, but it is finding a match if a part of the word is the same (one, oneTwo). If I add "else if" to the first "if" it always goes to the "else if".
The rest of the file prints different results for
printf("idTable string lenght:\t %u\n", strlen(idTable[index]));
and
printf("foundMatch string lenght:\t %u\n", strlen(foundMatch));
, unless I add printf("Index:\t %i\n", index);.
uint8_t getID(char *name) {
printf("\nInserted name:\t %s\n", name);
uint8_t index;
for (uint8_t r = 0; r < 255; r++) {
if (strstr(idTable[r], name) != NULL) {
printf("Found '%s' in position:\t %d\n", name, r);
index = r;
}
}
printf("Index:\t %i\n", index); // THIS LINE
char foundMatch[strlen(idTable[index])];
printf("idTable string lenght:\t %u\n", strlen(idTable[index]));
for (uint8_t c=0; c<strlen(idTable[index]); c++) {
foundMatch[c] = idTable[index][c];
}
printf("foundMatch string lenght:\t %u\n", strlen(foundMatch));
if (strcmp(foundMatch, nodeName) == 0) {
printf("Confirmed\n");
return index;
} else {
printf("Second test failed\n");
return 0;
}
}
Why am I getting this strange results and is there a better way to do this?
I don't know how you are initializing your idTable entries, but if you are using the method that you showed at the start of the question you'll have problems. You can't assume all of the space reserved by idTable is initialed to 0's, so idTable[43] isn't a null terminated string. Therefore idTable[43] need not compare equal to the null terminated string "tester".
Also your getID function doesn't return anything despite its signature. So it won't even compile as-is.
Here's a solution in actual C++, not C.
std::array<std::string, 255> idTable;
idTable.at(43) = "tester";
std::pair<std::size_t, std::size_t> findInIdTable(std::string const& what) {
for (unsigned i = 0; i < idTable.size(); ++i) {
std::size_t pos = idTable.at(i).find(what);
if (pos != std::string::npos) {
return std::make_pair(i, pos);
}
}
// if the code reaches this place, it means "not found". Choose how you want to deal with it
// my personal suggestion would be to return std::optional<std::pair<...> instead.
}
If you want to discard the pos value, it's easy to change as well.
Live On Coliru
In the category: Use C++
Of course, use std::array<char, 32> or std::string if possible. I stuck with your choices for this answer:
Live On Coliru
#include <algorithm>
#include <iostream>
#include <cstring>
char idTable[255][32] = { };
int main() {
using namespace std;
// initialize an entry
copy_n("tester", 7, idTable[43]);
// find match
auto match = [](const char* a) { return strcmp(a, "tester") == 0; };
auto index = find_if(begin(idTable), end(idTable), match) - idTable;
// print result
cout << "match at: " << index;
}
Prints
match at: 43
You need to add a nul to the end of the foundMatch array after copying in the idTable row:
foundMatch[strlen(idTable[index])] = '\0';
right before the 'foundMatch string lenght' (length) message.
strlen is an expensive function that walks the string every time. You should call that once, store it in a local variable, then reference that variable rather than calling strlen repeatedly.
I wrote this code to reverse strings. It works well, but when I enter short strings like "american beauty," it actually prints "ytuaeb nacirema2." This is my code. I would like to know what is wrong with my code that prints a random 2 at the end of the string. Thanks
// This program prompts the user to enter a string and displays it backwards.
#include <iostream>
#include <cstdlib>
using namespace std;
void printBackwards(char *strPtr); // Function prototype
int main() {
const int SIZE = 50;
char userString[SIZE];
char *strPtr;
cout << "Please enter a string (up to 49 characters)";
cin.getline(userString, SIZE);
printBackwards(userString);
}
//**************************************************************
// Definition of printBackwards. This function receives a *
// pointer to character and inverts the order of the characters*
// within it. *
//**************************************************************
void printBackwards(char *strPtr) {
const int SIZE = 50;
int length = 0;
char stringInverted[SIZE];
int count = 0;
char *strPtr1 = 0;
int stringSize;
int i = 0;
int sum = 0;
while (*strPtr != '\0') {
strPtr++; // Set the pointer at the end of the string.
sum++; // Add to sum.
}
strPtr--;
// Save the contents of strPtr on stringInverted on inverted order
while (count < sum) {
stringInverted[count] = *strPtr;
strPtr--;
count++;
}
// Add '\0' at the end of stringSize
stringInverted[count] == '\0';
cout << stringInverted << endl;
}
Thanks.
Your null termination is wrong. You're using == instead of =. You need to change:
stringInverted[count] == '\0';
into
stringInverted[count] = '\0';
// Add '\0' at the end of stringSize
stringInverted[count] == '\0';
Should use = here.
What is wrong with your code is that you do not even use strlen for counting the length of the string and you use fixed size strings (no malloc, or, gasp new[]), or the std::string (this is C++)! Even in plain C, not using strlen is always wrong because it is hand-optimized for the processor. What is worst, you have allocated the string to be returned (stringInverted) from the stack frame, which means when the function exits, the pointer is invalid and any time the code "works" is purely accidental.
To reverse a string on c++ you do this:
#include <iostream>
#include <string>
int main() {
std::string s = "asdfasdf";
std::string reversed (s.rbegin(), s.rend());
std::cout << reversed << std::endl;
}
To reverse a string in C99 you do this:
char *reverse(const char *string) {
int length = strlen(string);
char *rv = (char*)malloc(length + 1);
char *end = rv + length;
*end-- = 0;
for ( ; end >= rv; end --, string ++) {
*end = *string;
}
return rv;
}
and remember to free the returned pointer after use. All other answers so far are blatantly wrong :)