Start ATOI at a specific part in a string

Go To Last Post
41 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Strange question?  Maybe.

 

I have a string of characters which are a reading from a temperature probe.  The first character is SOH(start of Header) then the next few are teh actual reading with a decimal point in there.  ATOI is perfect as I only care about the numbers to the left of the decimal so by function it will stop converting once it sees the '.'

 

Problem is that my first character is SOH(0x01) which is not an ASCII number of 0 to 9 (0x30...0x39).

 

IS there a way to tell ATOI to start at location 2 in the string?

 

Jim

This topic has a solution.

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

Last Edited: Fri. Apr 10, 2020 - 12:42 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

atoi( const char *s ) in <stdlib.h>

 

You pass it a pointer to char.  Just set your pointer to the second char.

If pointer StrPtr is pointing to the first char, try:

 

x = atoi(++StrPtr);

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Tnaks chuck, but the compiler is not happy.

 

Here is what I have:

 

int cabinet_temperature;		//atoi result for inside cabinet temperature
unsigned char i2c_recv[10];				//i2c receive buffer

while(1)
{
    measure_temperature(cabinet_probe);
    cabinet_temperature = atoi(++i2c_recv);
}

 

 

The compiler spits back:

Severity   
Error        the expression must be a modifiable lvalue   

 

 

I openly admit I am not good with pointers.

 

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

Last Edited: Fri. Apr 10, 2020 - 02:11 AM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Apparently, I'm not good with pointers either.

 

How about:

cabinet_temperature = atoi(&(i2c_recv[1]));

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Chuck99 wrote:

Apparently, I'm not good with pointers either.

 

How about:

cabinet_temperature = atoi(&(i2c_recv[1]));

 

 

THAT WORKS!!  Thank you!!

 

Now I need to understand WHY that does what it does......  I know that the '&' points to teh direct address of a variable, but why in the example you posted above, it does not look like a pointer <using the '*'> but instead teh direct address.

 

I am guessing that somehow an extra step is being removed b not declaring an '*ptr' and loading that with the address to point to?

 

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Chuck99 wrote:

Apparently, I'm not good with pointers either.

The reason your first suggestion doesn't work is because (East coast) Jim's i2c_recv is an array, not a pointer.  As such it cannot be incremented.

 

Your second suggestion should work.  So should this:

cabinet_temperature = atoi(i2c_recv + 1);

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jgmdesign wrote:

Now I need to understand WHY that does what it does......  I know that the '&' points to teh direct address of a variable, but why in the example you posted above, it does not look like a pointer <using the '*'> but instead teh direct address.

 

I am guessing that somehow an extra step is being removed b not declaring an '*ptr' and loading that with the address to point to?

  i2c_recv     is an array of char.

  i2c_recv[1]  is a char.  Specifically, it is the 2nd char in the array.

&(i2c_recv[1]) is the address of the second char in the array.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Fri. Apr 10, 2020 - 02:51 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Joey, thanks for the explanation.

 

Edit:

I think I get it now.

i2c_recv is a pointer, but it is a constant, not a variable.

You can't increment it or otherwise change its value.

It must always point to the first element of the array.

 

But you can do:

unsigned char  * StrPtr;

unsigned char i2c_recv[10];

StrPtr = i2c_recv;

 

 

 

Last Edited: Fri. Apr 10, 2020 - 05:27 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In addition to the above:

 

`atoi` is a "dead" function that is not supposed to be used in modern code. It is kept around purely for compatibility with legacy code. String-to-number conversion in C standard library is implemented by functions from `strto...` group. You probably need `strtol` in your case.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Chuck99 wrote:
i2c_recv is a pointer, but it is a constant, not a variable.

 

No, this interpretation is still incorrect. `i2c_recv` is not a "constant pointer". It is not a pointer at all. It is an array. You are not allowed to increment an array. That is all there is to it.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Chuck99 wrote:
i2c_recv is a pointer, but it is a constant, not a variable.
Sort of.  In many respects it behaves like a pointer, but it is not a pointer.  It is an array.  You can pass it to functions which expect a pointer of the base type, but there are many ways in which it is not a pointer.  You've run across one of them.

 

Another is the sizeof operator.  Taking the sizeof an actual pointer will return the size of the pointer.  With AVR GCC, that's usually two bytes.  Taking the sizeof an array will return the size of the array in bytes, so:
 

char foo[20]
uint16_t bar[10];
int a = sizeof(foo);
int b = sizeof(bar);

Both a and b will contain 20.

 

Here's a good resource:

https://publications.gbdirect.co.uk/c_book/chapter5/

A summary from that chapter:

5.9. Summary

You have been introduced to arrays, pointers and the storage allocater. The last of the topics will prove to be more useful in the next chapter, but the other two are are central to the language.

 

You cannot use C properly without understanding the use of pointers. Arrays are simple and unsurprising, except for the fact that when it's used in an expression, an array name usually converts into a pointer to its first element; that often takes time to sink in.

 

The C approach to support for strings often causes raised eyebrows. The null-terminated array of character model is both powerful and flexible. The fact that string manipulation is not built in to the language at first glance seems to rule C out of serious contention for character-oriented work, yet that is exactly where the language scores well compared with the alternatives, at least when speed is important. All the same, it's hard work for the programmer.

 

Pointer arithmetic is easy and extremely convenient. It's harder for ex-assembler programmers to learn, because of the tendency to try to translate it into what they ‘know’ the machine is doing. However, much harder for people with very low-level experience is the idea of the non-equivalence of pointers of different types. Try hard to throw away the idea that pointers contain addresses (in the hardware sense) and it will repay the effort.

 

The facility to obtain arbitrary pieces of storage using malloc and the associated stuff is extremely important. You might wish to defer it for a while, but don't leave it for too long. An obvious feature of C programs written by inexperienced users is their dependence on fixed size arrays. Malloc gives you considerably more flexibility and is worth the effort to learn about.

 

The examples of the use of sizeof should help to eliminate a few common misconceptions about what it does. You may not use it all that often, but when you do need it, there's no substitute.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

C pointers & arrays:

 

http://c-faq.com/aryptr/

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
Pointer arithmetic is easy and extremely convenient. It's harder for ex-assembler programmers to learn, because of the tendency to try to translate it into what they ‘know’ the machine is doing.

 

AMEN!!

 

joeymorin wrote:
&(i2c_recv[1]) is the address of the second char in the array.

Which in my reading I figured out, but where I get confused is how the '*' and '&' are interpreted.

 

I was reading this:

https://www.tutorialspoint.com/c...

 

And it's a pretty good read.  But where I am getting confused is the implementation.

 

Now in my situation using ATOI, the (char *s) is looking for a pointer to an address for teh function to begin extraction/conversion? 

 

So if that is the case then using Chuck99's

atoi(&(i2c_recv[1]))

puts teh physical address of the array, second character in place of teh pointer?  Which if thats the case I get confused based on that link I posted.  From what I can see in order to get the value of the variable I need an extra step by assigning a pointer to teh address of teh variable that I want to get the value of.   SHEESH!!!!

 

Now if my reasoning is correct, does this mean I can simply have a generic *ptr for use at any time I need to point to something as opposed to directly hitting the variable(s) as needed?  It would seem wasteful to have a dozen pointers for a dozen variables where a single pointer could be used wherever needed.  I know that it is application dependent, I am just looking for generalisation.

 

awneil wrote:
(&(i2c_recv[1]))

Also a good piece of information.  Thanks!

 

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jgmdesign wrote:

Now in my situation using ATOI, the (char *s) is looking for a pointer to an address for teh function to begin extraction/conversion? 

You've fallen into one of the pitfalls mentioned in the summary above in #12:

Try hard to throw away the idea that pointers contain addresses (in the hardware sense) and it will repay the effort.

The parameter to atoi, namely char *s, means that the parameter needs to be a pointer to char.  When passing an array's name as the argument, this becomes a pointer to the first element in the array.  Likewise, the & unary operator produces a pointer to it's operand.

 

jgmdesign wrote:
puts teh physical address of the array, second character in place of teh pointer?
Again, same pitfall.  Forget about addresses.

 

With Chuck's:

&(i2c_recv[1])

... the & operator's operand is (i2c_recv[1]), which is a char, and therefore &(i2c_recv[1]) produces a pointer to that char, just what atoi() expects.

 

 

jgmdesign wrote:
Which if thats the case I get confused based on that link I posted
Your first warning should have been their claim that:

Pointers in C are easy and fun to learn

;-)

 

They seem to by trying to convey an understanding of pointers and arrays from the standpoint of an assembly language programmer, using address as a core concept.  While this can help with some initial understanding, it can get in the way as well.  A pointer is a thing which points to something else.  It really is as simple as that.  When I dereference a pointer, I get the thing it was pointing to.  That is, if ptr is a pointer to char, then *ptr gets me the char it is pointing to.  I can also get a pointer to something by using the unary & operator with the something as its operand.  That is, if foo is a char, then &foo gets me a pointer to that char.  It is a pointer like any other.  Since pointers can be dereferenced, and a dereferenced pointer gets me the thing the pointer is pointing to, then *(&foo) is another way of referring to foo.  So is *(&(*(&foo))).  So is *(&(*(&(*(&foo))))).  Clear as mud? ;-)

 

 

jgmdesign wrote:
Now if my reasoning is correct, does this mean I can simply have a generic *ptr for use at any time I need to point to something as opposed to directly hitting the variable(s) as needed?
I'm not certain I understand what you're asking.

 

For starters, pointers are typed.  That is, a pointer to, say, char is not the same as a pointer to, say, int.

 

Another important thing to remember is that pointers are types in and of themselves.  That's a hard one to swallow for some, perhaps mores so for assembly language programmers, where the notion of type is somewhat alien to begin with.

 

Yes, you can have a pointer for use any time you need to point to something, but you don't actually need a pointer variable.  In the case of the example in this thread, you could have:

char i2c_recv[10];    // <-- an array of char, with 10 elements.
char *ptr             // <-- a pointer to char.

ptr  = i2c_recv;      // <-- ptr now points to the first element of i2c_recv[].
ptr += 1;             // <-- ptr now points to the second element of i2c_recv[].

atoi(ptr);

This would have the same result as the other two options you've been shown:

atoi(&(i2c_recv[1]));

... and:

atoi(i2c_recv + 1);

In each case, atoi() is called with a pointer to the same char, namely a pointer to the second element in i2c_recv[].

 

The relationship between arrays and pointers can indeed be confusing.  I encourage you to have a look at the link I posted in #12.  They do a fairly good job of explaining it.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks joey, clear as thick mud it is!!

 

I have some reading to do.

 

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm intrigued by the over use of parentheses in this thread. What's wrong with simply using atoi(&i2c_recv[1]) ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

I'm intrigued by the over use of parentheses in this thread. What's wrong with simply using atoi(&i2c_recv[1]) ?

Nothing at all of course.  Cliff, as you know, parenthesis can be and are used frequently to disambiguate order of operations for the reader.  While the compiler knows that [] has higher precedence than &, adding the parenthesis can aid the uninitiated.  As mentioned in other recent threads, however, this may not be the case for all readers.

 

https://en.cppreference.com/w/c/language/operator_precedence

 

EDIT: sp

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Fri. Apr 10, 2020 - 08:41 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jgmdesign wrote:

awneil wrote:

(&(i2c_recv[1]))

 

Although it is the kind of thing I would write (though probably with less parentheses), I can't take credit for it this time!

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
I can also get a pointer to something by using the unary & operator with the something as its operand
Jim, here's a (possibly) helpful excerpt from The C Book:

What is this new unary &? It is usually described as the ‘address-of’ operator, since on many systems the pointer will hold the store address of the thing that it points to. If you understand what addresses are, then you will probably have more trouble than those who don't: thinking about pointers as if they were addresses generally leads to grief. What seems a perfectly reasonable address manipulation on processor X can almost always be shown to be impossible on manufacturer Y's washing machine controller which uses 17-bit addressing when it's on the spin cycle, and reverses the order of odd and even bits when it's out of bleach. (Admittedly, it's unlikely that anyone could get C to work an an architecture like that. But you should see some of the ones it does work on; they aren't much better.)

 

We will continue to use the term ‘address of’ though, because to invent a different one would be even worse.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:

atoi(&(i2c_recv[1]));

Seems easier to read (for me anyway) than:

joeymorin wrote:
atoi(&i2c_recv[1])

 

but it would be a pain to type all those "(" ")"!!!

 

Interesting discussion though.

Jim

 

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Parentheses  don't cost you anything more than minor wear on your fingers.

Yes,  they show how to evaluate an expression.

 

Personally,  I would say:

atoi(i2c_recv + 1);

which seems pretty intuitive.   However punters struggle with pointer arithmetic.   So if you are happier with:

atoi(&(i2c_recv[1]));

I suggest that you stick with it.   There is little doubt that it means "address of  (the second element of the array)"

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
There is little doubt that it means "address of  (the second element of the array)"
'Pointer to', not 'address of' ;-)

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
Parentheses  don't cost you anything more than minor wear on your fingers.

Similarly whitespace

atoi( &i2c_recv[1] );

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:

david.prentice wrote:

There is little doubt that it means "address of  (the second element of the array)"

 

'Pointer to', not 'address of' ;-)

 

In standard C/C++ terminology terms "pointer" and "address" are often used interchangeably, especially when we are talking about values (not variables). E.g. when referring to the result of unary `&`, one can use both "pointer" and "address". Both are correct.

 

When talking about an object of pointer type (a variable, an lvalue), the term "pointer" is preferable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AndreyT wrote:
Both are correct
Indeed.  However, as noted in The C Book (which is based upon the first C standard), they quite correctly note that any notion of address is implementation-specific.  Further, attempts to understand pointers w.r.t. addresses can lead inexperienced C programmers, especially if they are experienced assembly language programmers, down blind alleys of misunderstanding.

 

The book I mention still makes use of the address terminology, as it >>can<< be useful in some cases, but I believe it's core message that pointers and address are not self-same terminology is a valuable one.

 

AndreyT wrote:
In standard C/C++ terminology terms "pointer" and "address" are often used interchangeably
That is a source of misunderstanding.

 

The standard does not help us in that respect, as it has chosen to name the & unary operator the 'address of' operator.  That name is misleading.  Addresses are implementation-specific.  A better name would have been 'pointer to' operator, but what's done is done.

 

Indeed, memory layout is mandated by some aspects of the standard (such as the equivalence of array subscripting with pointer arithmetic/dereferencing), and the notion of address would seem to be implied, but they are in fact not.

 

The concept that a pointer is a thing which points to something else is excruciatingly simple.  So much so that we conjure up all manner of mental gymnastics in an attempt to understand it in the context of something more complex.  This, too, I believe, is the source of much misunderstanding.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is there any other (practical) way of referencing a "thing" than its address? If so, can you provide an example?

 

Thanks

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

ka7ehk wrote:

Is there any other (practical) way of referencing a "thing" than its address? If so, can you provide an example?

Yes.  It's called a pointer!

 

If you ask me to show you where my nose is, would I give you its address?  Or would I simply point to it?

 

Again, address is a machine-specific and therefore implementation-specific concept.  While it can be helpful to think of addresses when trying to visualise data/memory structure, the point I am trying but failing to make is that this is entirely unnecessary, and in many respects misleading.  The degree to which we see threads filled with posts by those struggling to understand pointers and how they fit into the language is perhaps an indication that this might be true.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But, what attribute of a thing is there that can be pointed to? A nose is one thing, defined by a cloud of points in space, but a chunk of code is not something that I am able  to point to.

 

Jim

 

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

Last Edited: Fri. Apr 10, 2020 - 09:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ka7ehk wrote:
but a chunk of code is not something that I am able  to point to
Of course it is.  With a function pointer.

 

In my analogy in # 28, the nose isn't the pointer, it's the thing being pointed to.  My finger (pencil, laser, ...) is the pointer.  It can be 'loaded' such that it points to any object, the type of which is compatible with its type.  I could not, for example, use my finger to point to, say, enlightenment.  Or world peace.  But I can point to a a nose, a hose, a cat, a bat...

 

The notion of address >>can apply<<.  When asked where I live, I might give you my address.  However, an address isn't needed.  I can point to my house with my trusty pointer.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But, here the context is executing code. Is there any other attribute other than address that can be used to identify a code thing other than address?

 

If you say "name" or some other identifying bit/byte pattern , then how is a given name associated with a specific piece of code? Other than exhaustive search for a name through the code, which is absurd from an execution standpoint, then the only thing left that I can see is "address".

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ka7ehk wrote:

But, here the context is executing code. Is there any other attribute other than address that can be used to identify a code thing other than address?

It's name.  Or a function pointer pointing to it.

 

I understand the desire to resolve the location of a piece of code to the numerical value embodied by the notion of an address.  And while an implementation may (most do) employ addresses 'under the hood', they are not part of the standard.  These are implementation details.

 

The piece of code representing the function foo() can be referenced by name, or by dereferencing a pointer which points to that function.  Nowhere in that statement, or the abstract machine model defined by the standard, is the notion of an address required, either to write the code, maintain the code, or understand the code.

 

ka7ehk wrote:
how is a given name associated with a specific piece of code?
The compiler/linker/loader takes care of that.  For example:

 

int foo(int val)
{
    return val / 38;
}

int main(void)
{
    int (*bar)(int);    // declare bar as pointer to a function taking an int and returning int
    bar = foo;          // point bar at foo
    return (*bar)(76);  // call foo by dereferencing bar
}

Nowhere in that code is an address, or an understanding of an address, required.  The expression (*bar)(76) doesn't mean run the code at the >>address<< in bar.  It means call the function pointed to by bar.  While in the architectures we are familiar with, the notion of address may seem familiar, it is entirely unrelated to the language description.

 

This is all a tempest in a teapot.  If seeing an address in your head helps you understand pointers, who am I to argue.  I maintain that addresses are not required to attain that understanding.  A face-value reading of the standard is sufficient.  A pointer points to something.  That's it.  You can make a pointer point to something by using the unary operator & against that something.  That's it.  You can look at or twiddle the something a pointer points at by dereferencing the pointer using the unary operator *.  That's it.  The word or concept of address is not required here.

ka7ehk wrote:
Other than exhaustive search for a name through the code, which is absurd from an execution standpoint, then the only thing left that I can see is "address".
Again, you don't have to do that at all.  When you call a function by name, you don't have to search for anything.  You only have to know the name of the function.  The compiler/environment has to know, but again that's implementation, not language spec.

 

I'll repeat the quote which started all of this:

Pointer arithmetic is easy and extremely convenient. It's harder for ex-assembler programmers to learn, because of the tendency to try to translate it into what they ‘know’ the machine is doing. However, much harder for people with very low-level experience is the idea of the non-equivalence of pointers of different types. Try hard to throw away the idea that pointers contain addresses (in the hardware sense) and it will repay the effort.

In this case, what you 'know' the machine is doing is loading an address and vectoring to it.  This is irrelevant to the abstract machine described by the C standard and the language, and it is irrelevant to the notion of pointers.

 

There's a reason we use high-level languages.  OK, many reasons.  One of them is to allow the coder to forget about details of implementation, and to focus on a common, agreed-upon, standardized language abstraction.  But old habits die hard!

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But, if the compiler has to know the name, then the compiler knows the address of the object the name references. So, even if that detail is hidden from the programmer, the mechanism must be there, under the hood. We, as programmers, may never have access to that address, but that still has to be the underlying mechanism.

 

So, do we not have to qualify with "accessible to the programmer" for the argument discussion to make any sense?

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ka7ehk wrote:
But, if the compiler has to know the name, then the compiler knows the address of the object the name references.
Which is entirely irrelevant to you as a programmer.  You simply invoke the code by name.
ka7ehk wrote:
So, even if that detail is hidden from the programmer, the mechanism must be there, under the hood
Which is why it is an implementation detail, and not a detail of the language specification.
ka7ehk wrote:
We, as programmers, may never have access to that address, but that still has to be the underlying mechanism.
No, it doesn't.  It only >>happens<< to be the underlying mechanism, as a consequence of the implementation, and the hardware on which it is implemented.  This is quite separate from the formal definition of a pointer as described by the language.

 

ka7ehk wrote:
So, do we not have to qualify with "accessible to the programmer" for the argument discussion to make any sense?
I don't see why.  The simple, human-language description of a pointer as 'a thing which points to another thing' invokes no notion of address.  >>You<< carry that into the discussion because your experience tells you that an address must underpin the implementation of a language with pointers on hardware with index registers and addressable memory spaces.  The fact that you are right is not relevant ;-)

 

And if you never have access to an address, why does it matter to think of things in terms of addresses? ;-)

 

EDIT: sp

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Sat. Apr 11, 2020 - 04:41 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I remain unconvinced. So, guess there is not much point in continuing this particular sub-thread.

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ka7ehk wrote:

I remain unconvinced. So, guess there is not much point in continuing this particular sub-thread.

 

Array and Pointers are a bit of a head scratch when you first come across them, there's even whole books written on just that subject.

 

For me, the light bulb moment was realising that a pointer has type; the compiler must know what type of thing it points to so that it can generate the right code to handle anything you do to the pointer...

 

#include <stdint.h>

uint8_t		a[5], *ap;
uint16_t	b[5], *bp;

void main(void)
{

    ap = a;
    *ap = 1;
    ap++;
    *ap = 2;

    bp = b;
    *bp = 1;
    bp++;
    *bp = 2;

    ...
    
}

 

The generated code for 'ap++' and 'bp++' is not the same even though they are both pointers.

#1 Hardware Problem? https://www.avrfreaks.net/forum/...

#2 Hardware Problem? Read AVR042.

#3 All grounds are not created equal

#4 Have you proved your chip is running at xxMHz?

#5 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand."

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
uint8_t		a[5], *ap;
uint16_t	b[5], *bp;

To me, this is unclear; I don't _see_ the * operator as belonging to the variable, but to the type:

uint8_t     a[5];
uint8_t *   ap;
uint16_t    b[5];
uint16_t *  bp;

The compiler doesn't care, obviously, but to me it's more obvious when I see it that way that there is a pointer to uint8_t, and it's called 'ap'. Purely  a matter of style and preference, of course. Equally I don't like hanging braces on the end of a keyword, even though some of my colleagues insist on it...

 

void prototype (parameter);      // this
void prototype( parameter );     // but not this please

Though this is an argument that can go on forever.

 

Regarding Joey and Jim's discussion; I think we're in that horrible quantum state that they're both right... Joey is quite correct to point out (sorry!) that the pointer is literally that, and the pointer has at the language level nothing to imply an address, but my word aren't there are lot of chips out there with legs labelled 'address 0-15' and 'data 0-7'? Without a doubt, in the majority of cases the object you're pointing at lives in physical memory at some stage of its life, but one can imagine an example of a variable held in one of a large number of registers at the time it is accessed. Obviously that doesn't have an address, but you can still - at the C level - use a pointer to it and the compiler will make sure that it all works.

 

Neil

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As MISRA says do not combine definition of different types of variable. It's all too easy to use

uint8_t *a,b,c;

when you really meant

uint8_t *a, *b, *c;

Last Edited: Sat. Apr 11, 2020 - 10:53 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

barnacle wrote:

To me, this is unclear; I don't _see_ the * operator as belonging to the variable, but to the type:

[pedant]

In this instance, * is not an operator, but more of a type modifier.

 

As a unary operator, it says "dereference this pointer and give me the thing it points to".  As a type modifier it says "declare this thing to be a pointer to a thing of the type on my left".

 

One does wonder why K&R didn't settle on something a little less confusing, but I suppose they were running out of special characters ;-)

[/pedant]

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

barnacle wrote:
To me, this is unclear; I don't _see_ the * operator as belonging to the variable, but to the type

 

Well, ultimately it does "belong to the type", since it describes the type of the variable. But syntactically the language says that `*` belongs to the variable, i.e. it affects the type of an individual declarator (possibly one of many within the declaration).

 

So, you have a choice of:

 

1. Following the underlying rules of the language and forcing yourself to accept and adopt this style of declaration

 

int *p, *q;

 

2. Or insisting on your vision. In that case you'll have to restrict yourself to one declarator per declaration, cause otherwise it might easily become even more unclear

 

int* p;
int* q;

 

Either approach is viable and acceptable. Both have many devotees. I personally prefer the first one.

 

Note that grouping various type-specific parts of the declarator to the left (with the type) in general case is not possible. E.g. when declaring an array

 

int a[10];

The `[10]` part also formally "belongs to the type", according to your own logic. However, you have no choice but to keep it attached to the variable. You cannot rewrite it as

 

int[10] a;

 

Last Edited: Sat. Apr 11, 2020 - 10:53 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AndreyT wrote:
according to your own logic.

 

Hey, who said there was any logic involved? :)

 

But... I *never* apply multiple name definitions to a type. One variable, one line.

 

Neil