Why is strcmp() not comparing a chararray and a char? - strcmp

I am writing a little script in PicoC to get my public IP-address for my Loxone Miniserver Go. So I always know my public IP. My Plan was to get the IP, split it into its 4 parts and set the integers to the programms outout.
Here is the script
// write program here in PicoC
char* append(char* addThis, char* toThis)
{
char* destination = (char*)malloc( strlen( addThis ) + strlen( toThis ) + 1 );
strcpy( destination, toThis );
strcat( destination, addThis );
return destination;
}
while(TRUE)
{
char *result = NULL;
result = httpget("checkip.dyndns.org","");
int j = 0;
char* p = NULL;
p = strstrskip(result,"Current IP Address: ");
j=strfind(p, "<", FALSE);
char ip[strlen(p)-j];
strncpy(ip,p,j);
char *first = malloc(4);
char *second = malloc(4);
char *third = malloc(4);
char *fourth = malloc(4);
char *tmp = NULL;
for (int i = 0; ip[i] != '\0'; i++) { //Made by me, so it may not be the most efficienet way
tmp = malloc(4);
if (strcmp(ip[i], ".") || ip[i] != '\0') //Error
tmp = append(tmp, &ip[i]);
if (strcmp(ip[i], ".") && first == NULL) { //Error
setlogtext("testing");
setlogtext(tmp);
strcpy(frist, tmp);
setlogtext(first);
} else if (strcmp(ip[i], ".") && second == NULL) { //Error
strcpy(second, tmp);
} else if (strcmp(ip[i], ".") && third == NULL) { //Error
strcpy(third, tmp);
} else if (strcmp(ip[i], ".") && fourth == NULL) { //Error
strcpy(fourth, tmp);
}
if (strcmp(ip[i], ".") || ip[i] == '\0')
free(tmp);
}
free(tmp);
setlogtext(first);
setoutput(0, atoi(first));
setoutput(1, atoi(second));
setoutput(2, atoi(third));
setoutput(3, atoi(fourth));
sleeps(15);
}
I also already read the documentation but I was not able to fix this issue.
Can anyone help me to fix it?

I don't know PicoC but I guess the problem here is the same you would have in C.
strcmp compares strings, it's just the way it is. Comparing a string and a char makes no sense: either your string is 1-character length, in which case you should directly compare chars ; or your string is not 1 character length, in which case it won't be equal to the character.
In your specific case, you should just compare characters, not strings:
if (ip[i] != '.' || ip[i] != '\0')

Related

Suggest logic with one loop to concatenate two strings without strcat

I have written a program to concatenate two strings without using strcat using two while loops for beginners. Need your suggestion to code it with one loop. Kindly share your logic thanks
char first[1000];
char second[2000];
char result[4000];
void concat(char *first, char *second, char *result){
int str_selector = 0;
int i = 0, result_pos = 0;
char *current_str = first;
while(1){
if(str_selector == 1 && current_str[i] == '\0'){
result[result_pos] = '\0';
break;
}
if(str_selector == 0)
current_str = first;
else
current_str = second;
if(current_str[i] != '\0'){
result[result_pos] = current_str[i];
result_pos++;
i++;
}
else{
i = 0;
str_selector = 1;
}
}
}

Remove Duplicate words (only if followed) from char array

I am a little bit stuck and cant find out what is wrong here.
I have an assignment to enter a sentence into char array and if there are duplicate and followed words(example : same same , diff diff. but not : same word same.) they should be removed.
here is the function I wrote:
void Same(char arr[], char temp[]){
int i = 0, j = 0, f = 0, *p, k = 0, counter = 0;
for (i = 0; i < strlen(arr); i++){
while (arr[i] != ' ' && i < strlen(arr)){
temp[k] = arr[i];
i++;
k++;
counter++;
}
temp[k] = '\0';
k = 0;
p = strstr((arr + i), (temp + j));
if (p != NULL && (*p == arr[i])){
for (f = 0; f < strlen(p); f++){
*p = '*';
p++;
}
f = 0;
}
j = counter;
}
}
strtok is a handy function to grab the next word from a list (strsep is a better one, but is less likely to be available on your system). Using strtok, an approach like the following might work, at least for simple examples...
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXPHRASELEN 1000
#define MAXTOKLEN 100
int main(int argc, char ** argv)
{
// Here is the sentence we are looking at
char * tmp = "This is a test and and another test";
// We will copy it to this variable
char phrase[MAXPHRASELEN+1];
strcpy(phrase, tmp);
// And will put the altered text in this variable
char new_phrase[MAXPHRASELEN+1];
// This will be the last word we looked at
char * lasttok = malloc(MAXTOKLEN+1);
// This will be the current word
char * tok = malloc(MAXTOKLEN+1);
// Both words are initially empty
new_phrase[0] = '\0';
lasttok[0] = '\0';
// Get the first word
lasttok = strtok(phrase, " ");
// If there is a word...
if (lasttok != NULL) {
// Put it in the altered text and add a space
strcat(new_phrase, lasttok);
strcat(new_phrase, " ");
// As long as there is a next word
while ( (tok = strtok(NULL, " ")) != NULL ) {
// See if it is the same as the last word
if (strcmp(tok,lasttok) != 0) {
// If it isn't, copy it to the altered text
strcat(new_phrase, tok);
// and add a space
strcat(new_phrase, " ");
// The current word becomes the last word
lasttok = tok;
}
}
}
// Print the lot
printf("%s\n", new_phrase);
}
If you really must write your own routine for grabbing the individual words, you could do worse than emulate strtok. It maintains a pointer to the beginning of current word in the string and puts a null character at the next separator (space character). When called again, it just moves the pointer to the character past the null, and puts another null after the next separator. Most string functions, when passed the pointer, will see the null as the end of the string and so just deal with the current word.
Minus comments, headers, and initialisation, it looks less threatening...
lasttok = strtok(phrase, " ");
if (lasttok != NULL) {
strcat(new_phrase, lasttok);
strcat(new_phrase, " ");
while ( (tok = strtok(NULL, " ")) != NULL ) {
if (strcmp(tok,lasttok) != 0) {
strcat(new_phrase, tok);
strcat(new_phrase, " ");
lasttok = tok;
}
}
}
printf("%s\n", new_phrase);

Compare two strings

I have a function that is supossed to compare to strings:
int string_compare(char *str1, char *str2){
while(*str1==*str2)
{
if ( *str1 == '\0' || *str2 == '\0' )
break;
str1++;
str2++;
}
if( *str1 == '\0' && *str2 == '\0' )
return 0;
else if(*str1 == '\0' && *str2 != '\0' )
return -1;
else
return 1;}
It shoud return 0 if those strings are identical , 1 if str1>str2 and -1 if str2
Edit: Now it shouldn't return any warning, but still it does not work correctly!
Follow the code given below to check whether the string is null.
if (myString != NULL) {
// doSomething
}
And if you want to compare two strings try these:
- strcmp(string1, string2)==0 if the CASE of string is also to be compared.
- strcmpi(string1,string2)==0 if the CASE of string is NOT to be compared.

How to get string from xml in COM

I have one array like this:
static WCHAR FilesToShow[][100] = { { L"start.cmd" },{ L"image.xml" }, { L"xyz" }};
as you see that there is "xyz" which I have to replace with some unique name. For this I have to read image.xml file.
Please can you tell me how can I do this.
I wrote a method like this:
PRIVATE WCHAR GetSystemName(WCHAR *pName)
{
WCHAR line;
wfstream in("image.xml");
WCHAR tmp;
bool begin_tag = false;
while (getline(in,line))
{
// strip whitespaces from the beginning
for (int i = 0; i < line.length(); i++)
{
if (line[i] == ' ' && tmp.size() == 0)
{
}
else
{
tmp += line[i];
}
}
if (wcswcs(tmp,"<SystemPath>") != NULL)
{
???????? how to get "vikash" from here <SystemPath>C:\Users\rs_user\Documents\RobotStudio\Systems\vikash</SystemPath>
}
else
{
continue;
}
}
return tmp;
}
I'm getting exception for wfstream, getline and line.length() method.
I have included fstream.h header file but I think It's not supported in COM.
Please help me how to solve this issue without parsing xml file.
If your xml-file is simple enough so that there is only a single tag with given name, you could do it like this:
#include <string>
#include <sstream>
#include <iostream>
std::wstring get_value(std::wistream & in, std::wstring const & tagname)
{
std::wstring text = std::wstring(std::istreambuf_iterator<std::wstring::value_type>(in),
std::istreambuf_iterator<std::wstring::value_type>());
std::wstring start_tag = L"<" + tagname + L">";
std::wstring end_tag = L"</" + tagname + L">";
std::wstring::size_type start = text.find(start_tag);
if (start == std::wstring::npos)
{
throw 123;
}
start += start_tag.length();
std::wstring::size_type end = text.find(end_tag);
if (end == std::wstring::npos)
{
throw 123;
}
return text.substr(start, end - start);
}
std::wstring get_substr_after(std::wstring const & str, wchar_t delim)
{
std::wstring::size_type pos = str.rfind(delim);
if (pos == std::wstring::npos)
{
throw 123;
}
return str.substr(pos + 1);
}
void stackoverflow()
{
std::wstring text(L"<foo>\n<bar>abc/def/ghi</bar>\n<baz>123/456/789</baz>\n</foo>\n");
std::wistringstream wiss(text);
std::wcout << text << std::endl;
std::wcout << get_substr_after(get_value(wiss, std::wstring(L"bar")), L'/') << std::endl;
}
The output of this program is:
<foo>
<bar>abc/def/ghi</bar>
<baz>123/456/789</baz>
</foo>
ghi
I hope that answered your question.
you have several issues here.
what you are getting are compiler errors and not exceptions
the header file to include is 'fstream' not 'fstream.h'.
make sure you have a line saying using namespace std;
You are declaring line as a variable of type WCHAR, so it is a single wide character, which surely is not a wstring object. Therefore line.length() is incorrect.
Why are you mixing C (wcswcs()) and C++ (STL) ? maybe you should re-design your function signature.
However, try the below function. I have modified the signature to return a pointer to WCHAR, and place the requested string in the buffer space provided by pName. I added a check to verify that the buffer is large enough to fit the name and the terminating NULL character.
WCHAR* GetSystemName(WCHAR *pName, size_t buflen)
{
wstring line;
wifstream in("image.xml");
WCHAR* tmp = NULL;
while (getline(in,line))
{
// strip whitespaces from the beginning
size_t beg_non_whitespace = line.find_first_not_of(L" \t");
if (beg_non_whitespace != wstring::npos)
{
line = line.substr( beg_non_whitespace );
}
size_t beg_system_path = line.find( L"<SystemPath>" );
if ( beg_system_path != wstring::npos )
{
// strip the tags (assuming closing tag is present)
size_t beg_data = beg_system_path + wstring( L"<SystemPath>" ).length();
size_t range = line.find( L"</SystemPath>" ) - beg_data;
line = line.substr( beg_data, range );
// get file name
size_t pos_last_backslash = line.find_last_of( L'\\' );
if ( pos_last_backslash != wstring::npos )
{
line = line.substr( pos_last_backslash + 1 );
if ( buflen <= line.length() )
{
// ERROR: pName buffer is not large enough to fit the string + terminating NULL character.
return NULL;
}
wcscpy( pName, line.c_str() );
tmp = pName;
break;
}
}
}
return tmp;
}
EDIT: Moreover, if you are using and/or parsing XML in other areas of your program, I strongly suggest using an XML parsing library such as Xerces-C or libXml2.
Thank you all for your answer. Here I got solution of my question.
PRIVATE WCHAR* GetNewSystemName()
{
WCHAR line[756];
WCHAR tempBuffer[100];
CComBSTR path = CurrentFolder.Path();
CComBSTR imagePath1 = L"rimageinfo.xml";
path.AppendBSTR(imagePath1);
std::wfstream in(path);
WCHAR tmp[756];
in.getline(line, 756);
WCHAR* buffer;
buffer = wcswcs(line, L"<SystemPath>");
WCHAR *dest = wcsstr(buffer, L"</SystemPath>");
int pos;
pos = dest - buffer;
unsigned int i = 0;
if (wcswcs(buffer,L"<SystemPath>") != NULL && wcswcs(buffer,L"</SystemPath>") != NULL)
{
for (; i < pos; i++)
{
if (buffer[i] == ' ' && sizeof(tmp) == 0)
{
}
else
{
tmp[i] = buffer[i];
}
}
tmp[i] = NULL;
//break;
}
int j = i;
for (; j > 0; j--)
{
if (tmp[j] == '\\')
{
break;
}
}
j++;
int k = 0;
for (; j < i ; j++)
{
System_Name[k] = tmp[j];
k++;
}
System_Name[k] = NULL;
return System_Name;

Replace specific character in a string in C++

I have a code like following -
Value = "Current &HT"; //this is value
void StringSet(const char * Value)
{
const char *Chk = NULL;
Chk = strpbrk(Value,"&");
if(Chk != NULL)
{
strncpy(const_cast<char *> (Chk),"&amp",4)
}
}
In above code I would like to replace "&" from Value with "&amp.It works fine if I have "&" single character but in current case strpbrk() return "&HT"and in below strncpy whole "&HT"is replaced.
Now I would like to know methods by which I can only replace a single character from a string.
You cannot replace one character in a C style string with several because you cannot know in a C style string how much room you have available to add new characters. You can only do this by allocating a new string and copying the old string to the new. Something like this
char* StringSet(const char* value)
{
// calculate how many bytes we need
size_t bytes = strlen(value) + 1;
for (const char* p = value; *p; ++p)
if (*p == '&')
bytes += 3;
// allocate the new string
char* new_value = new char[bytes];
// copy the old to the new and replace any & with &amp
char* q = new_value;
for (const char* p = value; *p; ++p)
{
*q = *p;
++q;
if (*p == '&')
{
memcpy(q, "amp", 3);
q += 3;
}
}
*q = '\0';
return new_value;
}
But this is terrible code. You really should use std::string.
I think you need some temp array to hold string past & and then replace & in original string and append temp array to original. Here is the above code modified, I believe you can use strstr instead of strchr it accepts char* as second argument.
void StringSet(char * Value)
{
char *Chk = NULL,*ptr = NULL;
Chk = strchr(Value,'&');
if(Chk != NULL)
{
ptr = Chk + 1;
char* p = (char*)malloc(sizeof(char) * strlen(ptr));
strcpy(p,ptr);
Value[Chk-Value] = '\0';
strcat(Value,"&amp");
strcat(Value,p);
free(p);
}
}
Thanks
Niraj Rathi
You should not modify a constant string, and certainly can't modify a string literal. Although it is much much better to use a std::string instead of dealing with resource management yourself, one way is to allocate a new c-style string and return a pointer to it:
char *StringSet(const char *Value) {
char buffer[256];
for (char *p = (char*)Value, *t = buffer; p[0] != 0; p++, t++) {
t[0] = p[0];
if (p[0] == '&') {
t[1] = 'a'; t[2] = 'm'; t[3] = 'p';
t += 3;
}
t[1] = 0;
}
char *t = new char[strlen(buffer)+1];
strcpy(t, buffer);
return t;
}
string str="Current &HT";
str.replace(str.find('&'),1,"&amp");