segmentation fault in swap function - c++

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.

Related

433 Receiver Arduino if statement

433 MHz receiver
Arduino environment
The transmitter sends Y, N or M which works just fine. The problem lies in the receivers code. The goal is, after the receiver has value message equal N, its suppose to trigger an if statement which would do a thing. I simply need to have a system that can determine if the receiver takes in a specific value.
void loop()
{
if (vw_get_message(message, &messageLength)) // Non-blocking
{
Serial.print("Received: ");
for (int i = 0; i < messageLength; i++)
{
Serial.write(message[i]);
const char *p = reinterpret_cast<const char*>(message);
if(p == "N")
{
Serial.print("if statement works when = N");
}
}
}
}
The problem, is it simply does not do the job, and after 2 weeks of struggle, I am completely at a loss. This code will compile and run, but the if statement is completely ignored.
if (p=="N") compares two pointers. While the contents they point to can be identical, that does not mean the pointers themselves are equal.
You may want strcmp (C style) or std::string::operator== (canonical C++)
Thankfully I was able to find a solution.
The working code:
void loop()
{
if (vw_get_message(message, &messageLength))
{
for (int i = 0; i < messageLength; i++)
{
const char *p = reinterpret_cast<const char*>(message);
if(p[0] == 'Y')
{
Serial.print(" - Yes");
break;
}
else if(p[0] == 'N')
{
Serial.print(" - No");
break;
}
}
Serial.println();
}
}
The point of const char *p = reinterpret_cast<const char*>(message); was to turn message, which is a byte, into a char. Yes p is a pointer, but it's pointing to a char, so with that, I can get the data in the char that p is pointing to by simply doing p[#]. A simple if statement can now be made
if(p[0] == 'M')
{
...
}
What type is message? Anyway, right now you are comparing value stored in p (so the address in memory, not what there is) to a string (notice double quotes). Why don't you just do
if(message[i] == 'N')
Single quotes here mean char literal.

Cannot find bounds of current function (Code::Blocks) C++

I am using the latest version of Code::Blocks. I have a function that passes in a string and a vector. The function compiles with no errors. However, when I run the debugger, it immediately leads me to line 118 (which I have noted) and gives me trouble. The error that comes up says "Cannot find bounds of current function".
Here is the function, which takes in a line of code of a variable declaration (like "var c=0"), and gets the variable of it and adds its value to the vector, v, a struct with an int value and string name:
char get_variable_declaration(string line, vector<variable> &v)
{
string b;
variable t;
char d[0];
int counter = 0;
int a;
for (int i = 0; i<line.size(); i++) {
if (line[i] == 'r' && counter != 1) {
b[0] = line [i+2];
counter ++;
}
if (line[i] == '=') {
b[1]=line[i+1];
}
}
t.name = b[0];
d[0] = b[1];
a = atoi (d);
t.value = a;
v.push_back (t);
return b[0];
//This function will take in a line of code
//that is confirmed to have a variable declaration
//it will add the variable to the list of
//vectors
}
Here is when it is called:
bool read_code(string file_name, vector<funct> &my_functions, vector<variable> & v)
{
vector<string> code;
string s;
std::size_t found;
bool flag;
funct new_function;
ifstream in;
in.open(file_name.c_str());
if(in.is_open())
{
//read in file line by line and put it into a vector called code
while(in.peek()!=EOF)
{
getline(in,s);
code.push_back(s);
}
in.clear();
in.close();
//read through each line of the code, determine if it's a variable or function (definition or call)
//here it makes reference to functions (listed following this one) which will actually decompose the line
//for information
for(int i=0;i<code.size();i++)
{
//check if it's a variable declaration
found = code[i].find("var");
if(found!=std::string::npos) //its a variable declaration
get_variable_declaration(code[i], v); //ERROR CANNOT FIND..
//check if it's a function. it'll go in the list of functions
found = code[i].find("funct");
if (found!=std::string::npos) //that means it's a function
{
new_function.funct_name=get_function_name(code[i]);
new_function.commands.clear();
i+=2; //skip over the open curly brace
flag=false;
while(!flag)
{
found = code[i].find("}");
if(found==std::string::npos)
{
new_function.commands.push_back(code[i]);
i++;
}
else
{
my_functions.push_back(new_function);
flag=true;
}
}
}
}
return true;
}
else
{
cout << "Cannot locate this file" << endl;
return false;
}
}
Disclaimer: Yes, this is a homework assignment. No, I am not looking for anyone to finish this assignment for me. But, I am still mostly a novice at coding, in need of some assistance, so I ask if you know what is going on, please help me address this issue. Thanks!
Edit: I have gotten this to work on another compiler w/o the text file I am reading from. Not sure if this is a universal issue, or one that the other compiler just didn't pick up on.
Multiple problems with this section of code:
string b;
for (int i = 0; i<line.size(); i++) {
if (line[i] == 'r' && counter != 1) {
b[0] = line [i+2];
counter ++;
}
if (line[i] == '=') {
b[1]=line[i+1];
}
}
Problems:
If the last character in line is 'r', undefined behavior can occur.
If the next to last character in line is 'r', undefined behavior can occur.
If the last character in line is '=', undefined behavior occurs.
Both assignments to b[0] and b[1] is undefined behavior. The b string is empty.
There are also other instances of undefined behavior that have been noted in the comments, which I won't duplicate.
I found the problem. To correctly use atoi, you cannot use a specific character from a string or character array. If you declare a char a[3], and you want to use atoi, you must use it like int value = atoi(a) and not value = atoi(a[2]). If you do not do it this way, it will cause a runtime error.

Encountering error in scanning a character in stacks [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
#include <stdio.h>
#define MAXLEN 100
typedef struct
{
char element[MAXLEN];
int top;
} stack;
stack init(stack s)
{
s.top=-1;
return s;
}
int isEmpty(stack s){
return(s.top==-1);
}
int isFull(stack s){
return (s.top==MAXLEN-1);
}
stack push(stack s,char ch){
if(s.top==MAXLEN-1){
printf("\n the stack is full\n");
return s;
}
else{
++s.top;
s.element[s.top]=ch;
return s;
}
}
stack pop(stack s){
if(s.top==-1){
printf("\n the stack is empty");
return s;
}
else{
--s.top;
return s;
}
}
void top(stack s){
if(s.top==-1){
printf("\n empty stack");
}
else
printf("%c",s.element[s.top]);
}
void print(stack s){
int i;
printf(" serial no character ");
for(i=0;i<s.top;++i){
printf(" %d %c \n",i,s.element[i]);
}
}
int main(){
stack s;
s.top=-1;
init(s);
char e;
int n,j=1,k;
while(j==1){
printf("\n enter your choice 1.push 2.pop 3.top 4.print 5.exit:");
scanf("%d",&n);
switch(n)
{
case 1:
printf("\n enter the element to be pushed: ");
scanf("%ch",&e);
s=push(s,e);
break;
case 2:
s=pop(s);
break;
case 3:
top(s);
break;
case 4:
print(s);
break;
case 5:
j=0;
break;
default:
printf("\n wrong choice entered enter correct one ");
break;
}
}
}
The error occurs after I compiled and run it and have scanned a character; it goes out of the switch and is not scanning the value of n for consecutive time and is just going into switch with the pre-assigned value and it comes out of switch and asks for n to enter t. In this way I am encountering space as character automatically in the stack elements and the top is getting doubled. Please help me with this. You can once compile it and check for yourself.
Change
scanf("%ch",&e); /* %ch ? */
To
scanf(" %c",&e); // notice a whitespace in the format string
As scanf("%c",&e); leaves a newline, which is consumed again.
which tells scanf to ignore whitespaces.
OR
if (scanf(" %c",&e) != 1)
//Print error
It doesn't take a lot to make the code work sanely. In the fixed code below, I pre-declare the functions because of the compiler options I use. An alternative is to define the functions as static.
#include <stdio.h>
#define MAXLEN 100
typedef struct
{
char element[MAXLEN];
int top;
} stack;
int isEmpty(stack s);
int isFull(stack s);
stack init(stack s);
stack pop(stack s);
stack push(stack s, char ch);
void print(stack s);
void top(stack s);
stack init(stack s)
{
s.top = -1;
return s;
}
int isEmpty(stack s)
{
return(s.top == -1);
}
int isFull(stack s)
{
return(s.top == MAXLEN - 1);
}
stack push(stack s, char ch)
{
if (s.top == MAXLEN - 1)
{
printf("the stack is full\n");
}
else
{
++s.top;
s.element[s.top] = ch;
}
return s;
}
stack pop(stack s)
{
if (s.top == -1)
{
printf("the stack is empty\n");
}
else
{
--s.top;
}
return s;
}
void top(stack s)
{
if (s.top == -1)
printf("empty stack\n");
else
printf("TOS: %c\n", s.element[s.top]);
}
void print(stack s)
{
int i;
printf("serial no character\n");
for (i = 0; i <= s.top; ++i)
{
printf(" %3d %c\n", i, s.element[i]);
}
}
int main(void)
{
stack s;
s.top = -1;
init(s);
char e;
int n, j = 1;
while (j == 1)
{
printf("\nenter your choice 1.push 2.pop 3.top 4.print 5.exit: ");
if (scanf("%d", &n) != 1)
{
fprintf(stderr, "Failed to read a number.\n");
return 1;
}
switch (n)
{
case 1:
printf("\nenter the element to be pushed: ");
if (scanf(" %c", &e) != 1)
{
fprintf(stderr, "Failed to read a character.\n");
return 1;
}
s = push(s, e);
break;
case 2:
s = pop(s);
break;
case 3:
top(s);
break;
case 4:
print(s);
break;
case 5:
j = 0;
break;
default:
printf("incorrect choice (%d not in range 1-5); enter correct one\n", n);
break;
}
}
return 0;
}
Apart from making the indentation consistent (I use uncrustify, but there are other tools that can do the job too), I added error checking to the scanf() statements, fixed the "%ch" format string (the h is superfluous, though mostly harmless), removed trailing spaces from printing, used a newline at the end of non-prompting printf() statements.
Your printing code wasn't printing enough; because of the way you're running your stack pointer, you need to print for (i = 0; i <= s.top; i++) with <= instead of <. A more orthodox way of using top has it showing the next space to use (so the number starts at zero and goes up to MAXLEN). There'd be a number of consequential changes to make.
However, there are some major curiosities left. You keep on passing stacks by value and returning them by value, rather than passing them by pointer. You're therefore passing 104 bytes to and from functions, which is quite a lot. In this code, efficiency isn't a big issue, but the style is unorthodox, shall we say. Your initialization stanza in main() is problematic, too:
stack s;
s.top = -1;
init(s);
The first line is fine. The second line sets top, and is OK in terms of "it works", but violates encapsulation. The next line has multiple problems. It takes a copy of the already initialized stack, sets top to -1, and returns the modified value. Your calling code, however, ignores the returned value.
If you passed pointers to your functions, you'd use:
void init(stack *s)
{
s->top = -1;
}
and then:
stack s;
init(&s);
If you pass values, you could use:
stack s;
s = init(s);
though that's a bit pointless and you could use:
stack init(void)
{
stack s;
s.top = -1;
return s;
}
and then call:
stack s = init();
Of these, passing by pointer is the normal mechanism for largish structures (where, if asked to specify 'largish', I'd say "16 bytes or more"). You can make exceptions on an informed basis, but be careful of the hidden costs of passing large structures by value. Also, changes made to the structures passed by value are not reflected in the calling function. You circumvent that by returning the modified value, but be cautious.

String comparison with struct element

I have piece of code like this in .c file, which detects, whether the tPerson.name is equal to one of the elements of const char* names[COUNT] or not:
define COUNT 3
...
typedef struct {
int age;
char *name;
} tPerson;
const char* names[COUNT] = {
"xxx", "yyy", "zzz"
};
....
char string[128];
strcpy(string, tPerson.name);//tPerson.name is already initizialed
int counter = 0;
while (counter != COUNT) {
if (strcmp(names[counter], string) == 0) {
counter++;
return 0;
}
}
...
All needed libraries are included. Compiler doesnt detect any errors or warnings, but program isnt working as it should - it does nothing after executing. This piece of code is only a part of the huge program, so I'd like to know, whether this construction is correct and somewhere else in the program is error or not. Thanks
You want to continue the loop if there's no match. Put the statement counter++; outside the if statement:
while (counter != COUNT) {
if (strcmp(names[counter], string) == 0) {
return 0;
}
counter++;
}
And use size_t for counter instead of int: size_t counter = 0;
You have return 0 before increasing the counter
if (strcmp(names[counter], string) == 0) {
return 0;
counter++;
}

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.