0

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?

  • 1
    Too many words and too few of the code. Post a [mcve] – Eugene Sh. Oct 24 '22 at 22:15
  • 1
    My crystal ball tells me that should be `if ((Qu = Instr(p, "qu", Equiv)) != NULL)`. If that is the first appearance of `Qu` after declaration, the compiler is right to complain. You'd be using it in a conditional if-test with no prior value assigned, and worse, not retaining the result of `Instr` which, per your description, locates the prospect string `"qu"`, returning a pointer to said-same if it exists. – WhozCraig Oct 24 '22 at 22:23
  • You'll want to start off with 2 or 3 books so that you can compare and contrast. The thing to watch out for is that many programming books are listed textbooks, written by cloistered professors, which the students have no choice but to purchase. Frankly, that means that most of them aren't very good. See the [The Definitive C Book Guide and List](https://stackoverflow.com/questions/562303/the-definitive-c-book-guide-and-list). – Mark Benningfield Oct 24 '22 at 22:28
  • 1
    Another way to spell the version that was probably intended would be `if (Qu = Instr(p, "qu", Equiv))`, which is different from the code in the post by just one character. Some compilers will warn about that form, as it is more often a mistake than not, but it is nonetheless valid and meaningful (and means something rather different from the version with `==`). – John Bollinger Oct 24 '22 at 22:30
  • @WozCraig Thank you for your comment. Your answer is basically same as John Bollinger's answer. Nice crystal ball by the way. Where can I get one? ;-) –  Oct 25 '22 at 06:12
  • @ Mark Benningfield Thank you for the list there are some books on the list that I was not aware of: –  Oct 25 '22 at 06:15

1 Answers1

1

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 by p 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 the if 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) = '$';
    }
John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • Thank you for such a detailed and insightful answer. You are right about `=` and `==` operators. The code is working as intended now. –  Oct 25 '22 at 06:07