-1

I have a given string

char *names = "ABC";

Now as part of understanding pointer and it casting I want to converting the string to it ascii code but using pointer.

Here what I have done thus far.

 char *name = "ABC";
 int *array;
 array = (int *) name;
 printf("the array value is %d ",*array);

but unfortunately I'm not able to understand why it print 4407873 as the value.

Note: Also I aware it can be done using atoi function but It would be truly helpful if I can understand how to do the above way.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
Ratatouille
  • 1,372
  • 5
  • 23
  • 50
  • 2
    The four bytes of the string (including terminator) in hexadecimal are `41 42 43 00`. Your machine is little-endian, so when reading those 4 bytes as `int` they are used the other way round, hex `00434241` which in decimal is `4407873`. But it is bad behaviour anyway. – Weather Vane Mar 07 '17 at 18:49
  • 1
    It's not clear what you're asking. What do you mean by the ascii code of "ABC"? What can be done using atoi? – Paul Hankin Mar 07 '17 at 18:49
  • 1
    It is exactly clear what you intend, but as it looks, you have a fundamental missunderstanding about pointer, casts and other fundamentals of the C language. Please do yourself a favour and read a C book. – too honest for this site Mar 07 '17 at 18:58
  • 1
    What number did you expect would be printed out? We can probably tell you how to get there. – Mark Plotnick Mar 07 '17 at 19:03
  • @Olaf I'm reading just it just that it very early stage. mean while can you point out what I'm missing above. – Ratatouille Mar 08 '17 at 02:29
  • 1
    Despite the name, `char` is not a character type -- it is an integral type. In many environments, `'A'==65` is true. –  Mar 08 '17 at 07:55
  • @Hurkyl You mean character constants, right? – Sourav Ghosh Mar 08 '17 at 07:56
  • Another aside: do not use `char *names = "ABC";`. Instead, use `const char *names = "ABC";`. The former is unsafe, since the resulting pointer really is pointing to an array of constant data that should not be modified; the only reason that line is allowed to compile is for backwards compatibility -- so that ancient code that existed before the language was standardized will still compile. (I think it's actually illegal in the most modern versions of the language; I'm not sure) –  Mar 08 '17 at 08:04

3 Answers3

1

In your code, using array as a pointer to integer

printf("the array value is %d ",*array);

where array was assigned a value like

array = (int *) name;

and name was defined as

char *name = "ABC";

violates strict aliasing rule. A char and an int are not compatible types, hence, the program is not valid.

Quoting from C11, chapter §6.3.2.3,

A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer. [...]

So, in case, a non-alias type is used to access the memory, it invokes undefined behavior.

Community
  • 1
  • 1
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • @SouravGhosh.I think I know what you are trying to say i.e int is would be 4 bytes(depending upon machine) and char is 1 byte, right? But can you explain that just as reference. – Ratatouille Mar 07 '17 at 18:45
  • @Ratatouille Yes, basically it's that but there are more to that. I've added a detailed and well-described resource to the strict aliasing in the answer, hope that helps. :) – Sourav Ghosh Mar 07 '17 at 18:49
  • @Ratatouille **Each** char is 1-byte, your *string literal* `"ABC"` is 4-bytes (e.g. `{ 'A', 'B', 'C', '\0' }` including the nul-terminating character). How the hardware expects the `int` to be stored in memory will depend on the *endianess* of your hardware. – David C. Rankin Mar 07 '17 at 18:49
  • 2
    @DavidC.Rankin: There is more to the effective type rules than just that and alignment. The compiler can safely apply optimisations, assuming the pointers cannot alias. – too honest for this site Mar 07 '17 at 19:00
  • This is not correct. Casts have nothing to do with aliasing rules. As long as certain (non aliasing related) requirements are met, casts can be performed among arbitrary types. – 2501 Mar 07 '17 at 19:16
  • @2501 well, the cast violates the aliasing, is not it? the cast-expression may be correct but the overall statement is incorrect due to violation of aliasing rule. Is there anything I am missing? – Sourav Ghosh Mar 07 '17 at 19:44
  • *the cast violates the aliasing, is not it?* No. As I said, casts have nothing to do with aliasing. The expression you're quoting does not violate aliasing. – 2501 Mar 07 '17 at 19:46
  • @Olaf, not to mince words, and I may be completely missing it, but how is the statement regarding the endianness of a machine being hardware dependent implicating effective type rules? – David C. Rankin Mar 07 '17 at 20:57
  • 1
    @2501: You can cast a pointer to another **and back**. That does not imply you may dereference the casted pointer value! In C the type of an object is defined by its **defined** type (or the type used for the last write to it for objects without a type, not by the type of the pointer used to access it. Anything else is inherently unsafe (legacy execptions for `char` excluded). – too honest for this site Mar 07 '17 at 21:34
  • I just wanted to make clear it is not the only issue. Actually it is one of the lesser concerns, because it is implementation-specific and predictable. – too honest for this site Mar 07 '17 at 21:38
  • @2501 OK, so I elaborated my thoughts, is it any better now? – Sourav Ghosh Mar 08 '17 at 07:55
  • You're quoting a rule, which is about conversions, that has nothing to do with your argument, which is about aliasing. – 2501 Mar 08 '17 at 07:56
  • @2501 Well in this case the cast + assignment makes the pointer conversion, so thought it would be relevant. – Sourav Ghosh Mar 08 '17 at 07:59
  • If you're arguing about aliasing, quote the rule for aliasing, not some other rule, that has nothing to do with the answer. – 2501 Mar 08 '17 at 08:01
1

Part of understanding pointers is understanding what not to do with them. And one of the main things you should not do with pointers is try to access an object of one type with a pointer to something that isn't a compatible type.

For example, reading elements from an array of char with a pointer-to-char is fine, and with a pointer-to-const char is fine too, but pointer-to-int is a big no-no.

The result of doing this is undefined behavior, which means that it could result in your program doing anything at all. (don't be fooled by what looks like a consistent behavior -- undefined behavior is allowed to do that too, and then will stop working sometime after you've convinced yourself it's OK to use undefined behavior and won't believe it's the cause of the bug)

0

In the C language, most types like int would typically be stored as a sequence of two or more consecutive bytes. Writing to an int* would convert the value written to a sequence of bytes and store them consecutively. Reading an int* would read a sequence of bytes and then convert them to an integer.

Not every sequence of consecutive integers may be read as another type, however. Implementations may impose three kinds of restrictions:

  1. On some implementations, some sequences of bytes might not represent values in certain types. For example, a floating-point value might be required to have its first byte be in the range 0-126 or 128-254; attempting to load a value whose first byte is 127 or 255 might trap in arbitrary fashion, depending upon the implementation.

  2. On many implementations, memory is physically divided into groups of 2, 4, or 8 bytes (sometimes called "words"), and objects of certain types and sizes may be required to start on the boundaries of correspondingly-sized groups (e.g. if "int" is 4 bytes, the system may only be able to load "int" quantities which fit in a single 4-byte word. An attempt to load an int* that would straddle a word boundary may fail with arbitrary consequences, depending upon the implementation.

  3. While some application fields may benefit greatly from being able to read and write storage using different types, many applications in other fields receive no benefit whatsoever. Compilers may generate more efficient code if they can assume that objects of one type won't be affected by pointers of another type, and the authors of the Standard make no attempt to require that implementations be suitable for any particular field. Consequently, the Standard does not require that implementations make any promises about the effects of writing storage as one type and reading it as another, even in cases where alignment requirements are satisfied and the bit patterns would be meaningful and useful.

    Implementations intended for use in fields where such translation is useful should specify cases where they promise to treat such actions in meaningful fashion, and implementations that don't do so may be unsuitable for use in purposes that would require such abilities, but implementations which are intended for use only with applications where such abilities would offer no benefit need not provide any such abilities beyond the bare minimums given in the Standard.

Note that the third point invokes a lot of heated argument because compiler writers fail to recognize that when the authors of the Standard were not trying require that all implementations be suitable for any particular purpose or application field, and thus made no attempt to mandate support for all behaviors that would be needed to make a compiler suitable for any particular purpose or field.

supercat
  • 77,689
  • 9
  • 166
  • 211