I am a 52-year-old chemical engineer who decided to change carrier, after some period of unemployment, to programming and made a mistake to choose C language to learn. In addition, English is not my native language, so be kind.
I am following "Illustrating C" by Donald Alcock. I am stuck with this problem for some time. It is a program called backslang on p105. I do not want to post the whole code, with the header file which includes custom string functions, it is about 250 SLOC.
if (Qu == Instr(p, "qu", Equiv))
{
*(Qu 1)='$';
}
What it supposed to do is: If it finds "qu"
in a string it will change the segment to "q$"
. However, char *Qu
pointer is declared inside the main() and not initialized. gcc -Wall
gives warning about it. I tried to initialize it with char *Qu = NULL
the behavior of code and error does not change. I traced it with GDB. The value of Qu is always 0x0 and when Instr function cannot find "qu" segment in string it enters to if block (0 == 0; TRUE or 1) and gives SEGMENTATION FAULT.
After a lot of research, I learned the difference between heap and stack. I have also learned that, in this kind of situation, I have to reserve memory on the heap using malloc(). However, at this point, the book has not reached to the point for that kind of knowledge and this code is supposed to work. Is this because of different C standard? The book was written in 1992. I tried the -ansi
and -std=c89
options without success. I still couldn't figure it out. What am I missing?
CodePudding user response:
After a lot of research, I learned the difference between heap and stack.
And that will no doubt prove to be useful knowledge as you move forward. But probably not for this particular issue.
I have also learned that, in this kind of situation, I have to reserve memory on the heap using malloc().
I'm not sure what type of situation you mean, but let me save you a lot of grief: malloc()
requires use of pointers, but use of pointers does not necessarily require malloc()
.
However, at this point, the book has not reached to the point for that kind of knowledge and this code is supposed to work.
I am confident that you do not need dynamic memory allocation here.
Consider the code presented:
if (Qu == Instr(p, "qu", Equiv)) { *(Qu 1)='$'; }
Given what you say it is supposed to do, and a little bit the chosen function name and the form of the code, it seems clear that the expectation is that
Instr()
will look for the substring"qu"
in a string (I guess given byp
here), and- it will return a pointer to the 'q' in that substring, or a null pointer if the substring is not found.
- The code is intended to both assign the return value to variable
Qu
, and test whether it is null, and in the event that it is non-null, to execute the body of theif
statement.
And it would do that if the if
condition were Qu = Instr(p, "qu", Equiv)
. This is because
- the (single)
=
is the assignment operator, - an assignment expression not only assigns the given value, but evaluates to the assigned value, and
- null pointers evaluate to false in boolean context, whereas non-null pointers evaluate to true in such contexts.
But ==
is an altogether different operator, an equality test as opposed to an assignment, and it is wrong here for reasons that you seem to understand.
It is unfortunately a fairly common error to use =
in conditional expressions where ==
was intended, to the extent that some compilers will actually warn about code that is correct for your case. It is much less common to make the opposite mistake, and when, as here, that logic is what is intended, it is usually best to express it differently. For maximum clarity, my recommendation would be
Qu = Instr(p, "qu", Equiv);
if (Qu != NULL)
{
*(Qu 1) = '$';
}