#c strcmp() isn't working as it should - strcmp

I want to compare between two char* so i do it with strcmp,
look, in debugging mode, both char* in strcmp gets the same value and still it
wont return 0, and it jumps over the if() condition instead of entering it:
here pic from the debugger:
http://img405.imageshack.us/img405/5218/111fi.jpg
Company FindCompany(CompanyL pcompanyList, int companyIdentityDigit)
{
Company companyFound;
char *psearchWord;
psearchWord = (char*)malloc(10*sizeof(char));
switch(companyIdentityDigit) {
case 0:
strcpy(psearchWord , "Pelephone");
break;
case 2:
strcpy(psearchWord , "Cellcom");
break;
case 4:
strcpy(psearchWord , "Orange");
break;
}
while(pcompanyList->next != NULL) {
if(strcmp(pcompanyList->thisCompany->pcompany , psearchWord) == 0) {
free(psearchWord);
return pcompanyList->thisCompany;
}
pcompanyList = pcompanyList->next;
}
free(psearchWord);
return NULL;
}
why is it??

Try a simple for loop to print out the characters in pcompanyList->thisCompany->pcompany one at a time:
for (int x = 0; x < strlen(pcompanyList->thisCompany->pcompany); x++)
printf("%c ", pcompanyList->thisCompany->pcompany[x]);
You can do this or check the length of each string to make sure there aren't hidden characters that aren't showing up in the debugger when you check the strings.

Related

Reverse a string. Not sure why this logic is wrong. C++

I am a beginner in solving algorithmic questions. Until now, I have only self-taught coding. So, I am not sure about the proper conventions.
I was trying to solve a question to reverse a string.There is some problem with the code but I am not sure what it is after debugging step-by-step.
class Solution {
public:
string reverseString(string s) {
int n = s.length();
string reverse;
for (int i=0;i<s.length();i++)
{
reverse[i] = s[n-1];
n=n-1;
}
return reverse;
}
};
Input: "Hello"
Output needed: "olleh"
My output: "olleh " (extra space)
Input: A man, a plan, a canal: Panama
Output: No output
I searched online for solutions. There were related to pointers. It would be great if someone helped me understand why this logic doesn't work and why using pointers is a better idea.
ALREADY GIVEN. CANNOT CHANGE:
string stringToString(string input) {
assert(input.length() >= 2);
string result;
for (int i = 1; i < input.length() -1; i++) {
char currentChar = input[i];
if (input[i] == '\\') {
char nextChar = input[i+1];
switch (nextChar) {
case '\"': result.push_back('\"'); break;
case '/' : result.push_back('/'); break;
case '\\': result.push_back('\\'); break;
case 'b' : result.push_back('\b'); break;
case 'f' : result.push_back('\f'); break;
case 'r' : result.push_back('\r'); break;
case 'n' : result.push_back('\n'); break;
case 't' : result.push_back('\t'); break;
default: break;
}
i++;
} else {
result.push_back(currentChar);
}
}
return result;
}
int main() {
string line;
while (getline(cin, line)) {
string s = stringToString(line);
string ret = Solution().reverseString(s);
string out = (ret);
cout << out << endl;
}
return 0;
}
As you create reverse, you have to pass the length of the string as an argument, else the created string will be of size 0. This could look like this:
string reverseString(string s) {
int n = s.length();
string reverse(n,'0');
for (int i=0;i<s.length();i++)
{
reverse[i] = s[n-1];
n=n-1;
}
return reverse;
}
Reversing a string is trivial. Just construct a new one from the reverse iterators:
std::string reverse_str(s.rbegin(), s.rend());
or
std::string reverse_str(s.crbegin(), s.crend());
Here's how I would write your function:
string reverseString(const string& s) {
return {s.crbegin(), s.crend()};
}
Try this out
class Solution {
public:
string reverseString(string s) {
//cout<<"inside func";
int n = s.length();
cout<<n<<endl;
char reverse[sizeof(char)*n];// reverse stores the reverse of original string s
int i= 0;
for ( i=0;i<s.length();i++)
{
reverse[i] = s[n-i-1];
}
return reverse;
}
}
int main()
{
string s,r;
Solution sol;
s= "hello";
r= sol.reverseString(s);
cout<<r<<endl;
cout<<r.length()<<endl;
return 0;
}
when i= 0, n-i-1= n-1 which is the last element of the original string s. So the first element of the reverse string is the last element of s. Next i becomes i+1 i.e 1. This time second element of the reverse string is the last but one element in string s. This procedure is repeated till i < s.length(). The element to get copied is for index i= n-1 and n becomes n-(n-1)-1= 0, so the last element of reverse string is the first element of s. After this the loop exists. No additional extra characters are added.

segmentation fault in swap function

im busy writing a line of code for my study.
I already have gotten quite far on the assignment but i keep running into the same problem.
On the swap function i keep running into a segmentation fault when a character is inputted(word & word2) that is not in the main 'dictionary' string.
Could someone explain to me what is causing the problem and how i can solve it? Sorry if anything isnt clear, i've just started learning c++.
code where segmentation fault occures:
void swapWords(char **dict, char *word, char *word2)
{
int i;
int d;
int x;
int y;
char *tmp;
while (1){
for(i = 0; i < MAX_NUMBER_OF_WORDS; i++)
{
if(strcmp(word, dict[i]) != 0)
{
if(i == MAX_NUMBER_OF_WORDS -1)
{
printf("Cannot swap words. Atleast one word missing in the dictionary.\n");
goto error;
}
}
else
{
x = i;
break;
}
}
for(d = 0; d < MAX_NUMBER_OF_WORDS; d++)
{
if(strcmp(word2, dict[d]) != 0)
{
if(d == MAX_NUMBER_OF_WORDS -1)
{
printf("Cannot swap words. Atleast one word missing in the dictionary.\n");
goto error;
}
}
else
{
y = d;
break;
}
}
tmp = dict[x];
dict[x] = dict[y];
dict[y] = tmp;
error: break;
}
}
The entire code:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#define MAX_NUMBER_OF_WORDS 10
void swapWords(char **dict, char *word, char *word2)
{
int i;
int d;
int x;
int y;
char *tmp;
while (1){
for(i = 0; i < MAX_NUMBER_OF_WORDS; i++)
{
if(strcmp(word, dict[i]) != 0)
{
if(i == MAX_NUMBER_OF_WORDS -1)
{
printf("Cannot swap words. Atleast one word missing in the dictionary.\n");
goto error;
}
}
else
{
x = i;
break;
}
}
for(d = 0; d < MAX_NUMBER_OF_WORDS; d++)
{
if(strcmp(word2, dict[d]) != 0)
{
if(d == MAX_NUMBER_OF_WORDS -1)
{
printf("Cannot swap words. Atleast one word missing in the dictionary.\n");
goto error;
}
}
else
{
y = d;
break;
}
}
tmp = dict[x];
dict[x] = dict[y];
dict[y] = tmp;
error: break;
}
}
void removeWord(char **dict, char *word)
{
int i;
int d;
for(i = 0; i < MAX_NUMBER_OF_WORDS; i++)
{
if(strcmp(dict[i], word) == 0)
{ dict[i] = NULL;
for(d = i+1; d < MAX_NUMBER_OF_WORDS; d++)
{ if(dict[d] == NULL)
{ dict[i] = dict[d-1];
dict[d-1] = NULL;
break;
}
}
break;
}
}
}
void printDict(char **dict)
{
int i = 0;
if(dict[0] == NULL)
{
printf("The dictionary is empty.\n");
}
else{
while (dict[i] != NULL)
{
printf("- %s\n", dict[i]);
i++;
}
}
}
void addWord(char **dict, char *word)
{
int d;
char *word1;
for(d = 0; d < MAX_NUMBER_OF_WORDS; d++)
{
if (dict[d] == NULL)
{
word1 = (char*) malloc(sizeof(char)*(strlen(word) + 1));
strcpy(word1, word);
dict[d] = word1;
break;
}
}
}
int numberOfWordsInDict(char **dict)
{
int i = 0;
int d;
for (d = 0; d < MAX_NUMBER_OF_WORDS; d++){
if(dict[d] != NULL)
{
i++;
}
}
return i;
}
int main()
{
char *dict[MAX_NUMBER_OF_WORDS] = {};
char word[36];
char word2[36];
char c;
int i;
while(printf("Command (a/p/r/s/q): "))
{
scanf(" %c", &c);
switch (c){
case 'p': printDict(dict);
break;
case 'a': printf("Enter a word: ");
scanf("%s", word);
addWord(dict, word);
break;
case 'n': i = numberOfWordsInDict(dict);
printf("%d\n", i);
break;
case 'r': printf("Remove a word: ");
scanf("%s", word);
removeWord(dict, word);
break;
case 's': printf("Swap two words:\n");
printf("Enter first word: ");
scanf("%s", word);
printf("Enter second word: ");
scanf("%s", word2);
swapWords(dict, word, word2);
break;
case 'q': return 0;
}
}
}
It will be most helpful to your studies as a student if you find the actual error yourself, though Marco and πάντα ῥεῖ may be right. However, here are a few things to think about, as this will definitely not be your last segfault problem as a programmer (I had at least 20 this month alone).
A segmentation fault is almost always caused by the code trying to modify or read memory that it doesn't have permission to read or modify. When the program starts, it is given a chunk of memory (RAM) to work with. For security reasons, no program is allowed to work with memory outside of that chunk. There are other limitations at play too.
As a general rule, if you try to read memory past the end of an array, you have a high risk of getting a segfault, or in other cases, garbled data. The official word on this actually comes from C, C++'s parent language, in that accessing past the end of an array causes "undefined behavior". Or, as it was once said on USENET, "it is legal for the compiler to make demons fly out of your nose". The behavior is totally unpredictable. Thankfully, that undefined behavior usually IS a segfault.
By the way, if you try to access an uninitialized array, similar weirdness can happen.
NOW, since you are accessing the elements of your array via a loop, another possible cause is that your loop is continuing beyond where you think it is. Sometimes it is helpful to modify your code so that the loop's iterator (i in your case) is printed out each iteration. This can help you catch if the loop is going beyond where it should.
In short, check...
Did I initialize all of my arrays before I tried to read or write
them?
Are my loops starting and stopping where I expected? Check for
"off-by-one" errors (i.e. starting at 1 instead of 0), infinite
loops (forgot to increment the iterator or the stop condition is
never true), and other logical errors.
Am I trying to read/write past the end of the array?
If I'm working with a C-string, did I forget the NULL terminator?
In addition to your debugger, which you should learn how to use well, tools like valgrind are instrumental in finding the cause of memory errors. Oftentimes, it can point you to the exact line of code where the segfault is occuring.
I had figured out myself the problem was in the strcmp. I know that figuring out a problem by myself is the best way to learn and I tried, but I just couldn't figure out why it was returning a seg fault. As this is my fifth assignment I'm only just getting to know how array's and pointers work. I assumed that the array was already initialized as 'NULL', as seen I was already comparing the pointer to 'NULL' in the addWord function. To assume this is ofcourse very stupid of me. I might not have figured the problem out by myself, yet it is still something I will not be forgetting anymore.
Most probably the segmentation fault happens here:
if(strcmp(word, dict[i]) != 0)
Infact it is quite likely that that i > becomes bigger than the size of your dict and if your dict has 3 elements and you try to access the 4th you are accessing an unknown area or ram and that causes a segmentation fault.
The solution is to make sure your for loop stops at the last element of the dictionary with the solution πάντα ῥεῖ has proposed in the above comment.

Writing an atoi to convert string to integer

I am writing an atoi to convert string to integer. Here is my code of atoi()function
int atoi(string str) {
int num=0;
int sign=1;
int len=str.size();
int i=0;
if(str[i]==' '&& i<len) i++;
if(str[i]=='+') i++;
if(str[i]=='-') {i++;sign=-1;}
for(;i<len;i++){
if(str[i]==' ') break;
if(str[i]<'0' || str[i]>'9') break;
if(INT_MAX/10<num || INT_MAX/10==num && INT_MAX%10<(str[i]-'0'))
{ return sign==-1 ?INT_MIN:INT_MAX;
break;
}
num=num*10+str[i]-'0';
}
return num*sign;
}
However, when input '1', output is 0, Why is that please?
well the code is kind of buggy:
this if(str[i]<'0' || str[i]>'9') break; won't get you very far; if you input 12aaa you want your method to return some error code or nothing, not the integer part of the string.
I don't even know what this is supposed to be....
if(INT_MAX/10<num || INT_MAX/10==num && INT_MAX%10<(str[i]-'0'))
{ return sign==-1 ?INT_MIN:INT_MAX;
break;
}
Get rid of the last if statement I highlighted, correct the first one so that the code does not try to convert anything other than valid integer strings, and the code should work.

Printing null character when input is odd character amount

I've been toying with this c program for a while, and I can't seem to figure out what I'm missing.
In the very bottom of my code, I have a function that replaces every other word with a "-".
My problem is that when I enter an odd numbered word, such as "Cat", "dog", "hamburger", it will place a "-" in what I think is the null character position, though I have not been able to debunk it.
Thank you for your help!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void replace(char w[]);
int main( )
{
char w[100], x[100], y[100];
int z = 0;
printf("Player 1, please enter the secret word: ");
fgets(x,100,stdin);
// system("clear");
while( strcmp(x,y) != 0 )
{
strcpy(w,x);
// printf("\nLength of String : %d", strlen(w)-1);
replace(w);
printf("Player 2, the word is %s\n",w);
printf("Player 2, please guess the word: ");
fgets(y,100,stdin);
z++;
if( strcmp(x,y) != 0 )
{
printf("Wrong. Try again.\n");
}
else
{
//system("clear");
printf("Correct!\n");
printf("It took you %d attempt(s).\n",z);
switch (z)
{
case 1 :
case 2 :
printf("A. Awesome work!");
{break;}
case 3 :
case 4 :
printf("B. Best, that was!");
{break;}
case 5 :
case 6 :
printf("C. Concentrate next time!");
{break;}
case 7 :
printf("D. Don't quit your day job.");
{break;}
default :
printf("F. Failure.");
{break;}
}
}
}
getch();
}
void replace(char w[])
{
int a;
a = 0;
while (w[a] != '\0')
{
if (a % 2 != 0)
{
w[a] = '-';
a++;
}
if (w[a] != '\0')
{
a++;
}
else
{
break;
}
}
}
From the fgets manual;
fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer. A terminating null byte (\0) is stored after the last character in the buffer.
The newline entered is what you're replacing.
You can implement like this...
int a;
int len;
a = 0;
len = strlen(w);
if(len%2 == 0)
len = len-1;
while (len!=a)
{
if (a % 2 != 0)
{
w[a] = '-';
a++;
}
if (w[a] != '\0')
{
a++;
}
else
{
break;
}
}
I think replacing fgets with just gets will work:
Try:
//fgets(x,100,stdin);
gets(x);
and
//fgets(y,100,stdin);
gets(y);
That will be enough I think.
The problem is caused by the additional '\n' character in the char array passed to the replace function.
For instance, when the input is "Cat", the passed char[] w contains {'C', 'a', 't', '\n', '\0'};
The additional '\n' also gets replaced with "-" character.
The following will solve this problem.
while (w[a] != '\0')
{
if (w[a] != '\0' && w[a] != '\n')
{
if (a % 2 != 0)
{
w[a] = '-';
}
a++;
}
else
{
break;
}
}
As a bit of an aside, can I suggest structuring your replace() code differently
void replace(char charw[])
{
int length=strlen(charw);
int i;
for (i=0;i<length;i++)
{
if (i%2==1) /*yes, i%2 would also work, but lets not get too clever*/
{charw[i]='-';}
}
}
This is far more readable. Breaking in the middle of a loop...not so much.

C++ : read csv file with fgetc and separate words on semicolon ";"

I have to read in a csv file with 5 fields (int , char[], char[], char[], float) that looks like that :
2345678;Meier;Hans;12.10.1985;2.4;
1234567;Müller;Fritz;17.05.1990;1.9;
I have to put the fields in a struct, and then put the struct after one line is complete, into a array of the struct type ...
for the learning effect, we are only allowed to use LOW-LEVEL coding, and only use functions like fgetc, strcpy and no strings, only char[]...
Now I made my algorithm to read the textfile character by character, but I have problems separating them correctly, putting them together again and assigning them to the struct fields correctly. Here is my Code:
#include <cstdlib>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string.h>
using namespace std;
int main(int argc, char **argv)
{
struct Stud{
long matrnr;
char vorname[30];
char name[30];
char datum[30];
float note;
};
const int MAX = 30;
Stud stud;
Stud mystud[30]; // <<-- Array of "Stud" type
//memset((void*)mystud,0,sizeof(mystud) * sizeof(Stud));
int wordCounter(0);
int i(0); //thats the charCounter or index
int studentCounter(0);
char wort[MAX];
//int matrnr;
//char vorname[MAX];
//char name[MAX];
//char datum[MAX];
//float note;
FILE * pFile;
int cnr(0);
pFile=fopen("studentendaten.txt","r");
if (pFile==nullptr)
{
perror ("Fehler beim öffnen der Datei");
}
else
{
while (cnr != EOF)
{
(cnr=fgetc(pFile)) ;
if ((char)cnr == '\n') {
mystud[studentCounter] = stud;
studentCounter++;
continue;
}
if ((char)cnr == ';') {
wort[i] = '\0';
switch (wordCounter % 5) {
case 0:
stud.matrnr = atol(wort);
break;
case 1:
strcpy(stud.name, wort);
break;
case 2:
strcpy(stud.vorname, wort);
break;
case 3:
strcpy(stud.datum,wort);
break;
case 4:
stud.note = atof(wort);
break;
}
wordCounter++;
i = 0;
continue;
}
if (wordCounter % 5 == 0 && (char)cnr != ';') {
wort[i] = (char)cnr;
i++;
//stud.matrnr = atol(wort);
}
if (wordCounter % 5 == 1) {
wort[i] = (char)cnr;
i++;
//strcpy(stud.name, wort);
}
if (wordCounter % 5 == 2) {
wort[i] = (char)cnr;
i++;
//strcpy(stud.vorname, wort);
}
if (wordCounter % 5 == 3) {
wort[i] = (char)cnr;
i++;
//strcpy(stud.datum,wort);
}
if (wordCounter % 5 == 4) {
wort[i] = (char)cnr;
i++;
//stud.note = atof(wort);
}
}
fclose (pFile);
}
for (int i(0) ; i <= studentCounter; i++) {
cout <<mystud[i].matrnr << " " << mystud[i].name << " " << mystud[i].vorname <<" "
<< mystud[i].datum <<" " << mystud[i].note << endl;
//printf("%5ld %5s %5s %5s %5f \n",mystud[i].matrnr,mystud[i].name,mystud[i].vorname,mystud[i].datum,mystud[i].note);
}
return 0;
}
I am not sure if it has to do with a wrong increment variables, or the fact that I don't put an '\0' at the end of my wort[] array..and therefore not recognizing the end of my array? And if so, how do I do it without knowing where the end exactly is... ? (I don't know the length of the words..)
EDIT: I updated my code again, the only thing that wonders me is that the LAST LINE IS NOT BEING CORRECTLY PARSED , its showing some rubbish, and I can't see the error in my code...
2345678;Meier;Hans;12.10.1985;2.4;
1234567;Müller;Fritz;17.05.1990;1.9;
8392019;Thomas;Kretschmer;28.3.1920;2.5;
3471144;Mensch;Arbeit;29.2.2013;4.5;
2039482;Test;Test;30.20.2031;2.0;
7584932;Bau;Maschine;02.02.2010;2.3;
2345678;Meier;Hans;12.10.1985;2.4;
1234567;Müller;Fritz;17.05.1990;1.9;
8392019;Thomas;Kretschmer;28.3.1920;2.5;
3471144;Mensch;Arbeit;29.2.2013;4.5;
2039482;Test;Test;30.20.2031;2.0;
7584932;Bau;Maschine;02.02.2010;2.3;
2345678;Meier;Hans;12.10.1985;2.4;
1234567;Müller;Fritz;17.05.1990;1.9;
8392019;Thomas;Kretschmer;28.3.1920;2.5;
3471144;Mensch;Arbeit;29.2.2013;4.5;
2039482;Test;Test;30.20.2031;2.0;
7584932;Bau;Maschine;02.02.2010;2.3;
2345678;Meier;Hans;12.10.1985;2.4;
1234567;Müller;Fritz;17.05.1990;1.9;
8392019;Thomas;Kretschmer;28.3.1920;2.5;
3471144;Mensch;Arbeit;29.2.2013;4.5;
2039482;Test;Test;30.20.2031;2.0;
7584932;Bau;Maschine;02.02.2010;2.3;
Suggestion: use a case structure for the parsing, and make yourself a "copyToSemicolon" function: then you can write things like
sIndexCount = 0;
char temp[50];
while((cnr=fgetc(pFile)) != EOF) {
offset = 0;
for(var = 0; var < 5; var++ {
switch(var) {
case 0:
offset = copyToSemicolon(temp, cnr, offset) + 1;
stud.matrnr = atoi(temp);
break;
case 1:
offset = copyToSemicolon(mystud[sIndexCount].vorname, cnr, offset) + 1;
break;
... etc
}
}
sIndexCount++;
if(sIndexCount == 50) break; // in case the input file is longer than our structure
}
And you need a function copyToSemicolon that takes two char* pointers as inputs, and that copies characters from the second string (starting at offset) until it reaches either a semicolon or the end of line - and that returns the offset it reached (last character read).
int copyToSemicolon(char* dest, char* source, int offset) {
while(source[offset] != ';' && source[offset] != '\n') {
*dest = source[offset++];
dest++;
}
return offset;
}
EDIT strtok method:
sIndexCount = 0;
char temp[50];
while((cnr=fgetc(pFile)) != EOF) {
offset = 0;
temp = strtok(cnr, ';');
for(var = 0; var < 5; var++ {
switch(var) {
case 0:
stud.matrnr = atoi(temp);
break;
case 1:
strcpy(mystud[sIndexCount].vorname, strtok(NULL, ';'));
break;
... etc
case 4:
mystud[sIndexCount].note = atof(strtok(NULL, '\n'));
}
}
sIndexCount++;
if(sIndexCount == 50) break; // in case the input file is longer than our structure
}
One issue that I am seeing is that your code copies or parses one character at a time, such that when you're reading 2345678;Meier;Hans;12.10.1985;2.4; you first set stud.matrnr to 2, then 23, then 234, then 2345, then 23456, then 234567, then 2345678. Similarly, for stud.name, you first set it to M, then the Me, then to Mei, etc. I propose to you to think of things in a different way. I'll give you some pseudocode:
while (!eof) {
get character from file
if (character isn't ';' and isn't '\n') {
copy character into buffer (increment buffer index)
} else if (character is ';') {
it's the end of a word. Put it in its place - turn it to an int, copy it, whatever
reset the buffer
} else if (character is '\n') {
it's the end of the last word, and the end of the line. Handle the last word
reset the buffer
copy the structure
}
}
This should make life a lot easier on you. You're not changing your data nearly as much, and if you need to debug, you can focus on each part on its own.
Generally, in programming, the first step is making sure you can say in your native speaking language what you want to do, then it's easier to translate it to code. You're close with you implementation, and you can make it work. Just be sure you can explain what should be happening when you see ';' or '\n'.
Since you have tagged this as C++, you should consider using std::getline for reading the line from the file, the use std::getline(file, text_before_semicolon, ';') for parsing the fields.
You could also use std::istringstream for converting the textual representation in the text line to internal numeric format.