Author Topic: C pointer confusion on char arrays  (Read 5242 times)

0 Members and 1 Guest are viewing this topic.

Offline VekettiTopic starter

  • Regular Contributor
  • *
  • Posts: 188
  • Country: fi
C pointer confusion on char arrays
« on: December 02, 2023, 08:20:47 pm »
Dear All,

I'm bit confused on warnings regarding pointers and char arrays. When calling function and having "&" for the char array, it gives error "incompatible pointer type. If I leave this ampersand out, no warning. So should it be left out for char arrays?

Second issue is that in "strlen(*text)" it somehow treats that as signed, even though it is declared as unsigned. Why is that and how to overcome this so that it is treated as unsigned?

Here's the code (warnings added as a comment to corresponding line):
Code: [Select]
unsigned char text[30] = "Hello";

int main(void)
{
ManipulateString(&text); // Warning: incompatible pointer type
}


void ManipulateString(unsigned char* text[])
{
// do something
uint8_t LengthOfString,i;
LengthOfString = strlen(*text); // warning: pointer targets in passing argument 1 of 'strlen' differ in signedness
     for (i=LengthOfString ; i < 16 ; i++)
     {
      if (i == LengthOfString) {
         *text[i] = 'p';
      }
      else if (i == LengthOfString+1)
  {
      *text[i] = 'p';
  }
      else if (i == LengthOfString+2)
  {
      *text[i] = 'm';
  }
      else *text[i] = 32;
     }
}

And last, I'm bit unsure is it even needed to declare char as unsigned when there are characters? Character ascii codes are all positive values so if it is not declared as unsigned I only get characters from 0 to 127?

I have a feeling that I don't need to declare char as unsigned and also no need to use ampersand on that function...

Thank you in advance.

Edit: incorrect topic name. Was C# when it should have been C
« Last Edit: December 02, 2023, 08:49:52 pm by Veketti »
 

Offline MarkT

  • Frequent Contributor
  • **
  • Posts: 393
  • Country: gb
Re: C# pointer confusion on char arrays
« Reply #1 on: December 02, 2023, 08:31:27 pm »
You other confusion is between C# and C++ I think!

In C and C++ an array is implemented as a pointer, so you can pass a char[] as a char* for instance.

Code: [Select]
void fun(char * param)
{
  ....
}

void foo()
{
  char array[30];
  fun(array);       // pass as pointer
  fun(&array[0]); // exactly the same thing
  fun(&array);     // wrong, as this has type char**
}

And of course char is not the same as unsigned char, so they are different, incompatible types, so thus their pointer types are also incompatible.

strlen returns size_t, not uint8_t, so respect that.  Whether size_t is signed or not is beyond your control I believe.
« Last Edit: December 02, 2023, 08:34:36 pm by MarkT »
 
The following users thanked this post: Veketti

Offline u666sa

  • Frequent Contributor
  • **
  • Posts: 351
  • Country: ru
Re: C# pointer confusion on char arrays
« Reply #2 on: December 02, 2023, 08:33:28 pm »
I don't know C# so this advice take with a grain of salt, C++ programmer giving a C# programmer advice.

Code: [Select]
int main() {
    ManipulateString(static_cast<unsigned char*>(&text));
}


Option two is to use #pragma warn precompiler directives. You remove said warning before you call that function, and add it back up once you call it. Either way it is on crutches. Your original function should look something like this instead:

Code: [Select]
string& ManipulateString(string& text) {
    return string;
}

Instead of unsafe pointers, you should use build in class string, take a reference, manipulate reference, and return reference.
 
The following users thanked this post: Veketti

Online IanB

  • Super Contributor
  • ***
  • Posts: 12437
  • Country: us
Re: C pointer confusion on char arrays
« Reply #3 on: December 02, 2023, 09:17:42 pm »
I'm bit confused on warnings regarding pointers and char arrays.

I think you are getting yourself confused because you have not adequately read and understood a book or a primer on the C language and especially how arrays and pointers work. Going through "The C Programming Language" by K&R chapter by chapter would always be a good start.

In particular, C treats arrays and pointers as equivalent. So you should proceed as below.

There are various other issues with your code sample that I do not have time to go into. Others here may help, and you will learn with time and practice.

Code: [Select]
#include <string.h>
#include <stdio.h>

static char text[30] = "hello";

size_t ManipulateString(char text[]);

int main(void)
{
    size_t length;
    length = ManipulateString(text);
    printf("Length of string is %d", length);
}

size_t ManipulateString(char text[])
{
    size_t length;

    length = strlen(text);

    /* do other things here */

    /* return final length of string */
    return length;
}
« Last Edit: December 02, 2023, 09:30:50 pm by IanB »
 
The following users thanked this post: Veketti

Online magic

  • Super Contributor
  • ***
  • Posts: 7291
  • Country: pl
Re: C pointer confusion on char arrays
« Reply #4 on: December 02, 2023, 09:40:56 pm »
As suggested above, you probably want "char text[]" or "char *text". The type you declared is "(a pointer to) an array of pointers to char" rather than "a pointer to an array of char". This type is commonly used for "argv" in "main", for example, which is an array of command line arguments supplied to the program, but it would be awkward and unusual to store a single text in such manner.

Secondly, whole thing could be rewritten as:
Code: [Select]
text[length] = 'p';
text[length+1] = 'p';
text[length+2] = 'm';
for (i = length+3; i < 16; i++)
    text[i] = ' ';

Assuming that enough space is guaranteed to exist. If length+2 can be greater than 15 then it's obviously not going to work.

And the last line could probably use memset instead, but memset's "count" argument is size_t which is unsigned and therefore passing a negative number (by naively writing 16-(length+3) when length is almost 16 already) would result in a lot of random memory being overwritten. A corsesponding signed type is ssize_t but I think it's only defined in POSIX (i.e. Unix, Linux, OSX, etc).
« Last Edit: December 02, 2023, 09:55:11 pm by magic »
 
The following users thanked this post: Veketti

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6305
  • Country: es
Re: C pointer confusion on char arrays
« Reply #5 on: December 02, 2023, 09:50:11 pm »
With buffer overrun protection:
Code: [Select]
char text_hi[30] = "Hello";                             // Avoid calling a global variable same as function arguments

ManipulateString(text_hi, sizeof(text_hi));             // array name without index makes a pointer.

void ManipulateString(char * text, uint8_t size)
{
    char *ppm = "ppm ";                                 // ppm string
    char *s = text;                                     // temporal pointer variable to use for own strlen
    uint8_t len = 0;

    while(*s++) len++;                                  // This is basically strlen. A C string is always NULL ended (after "ppm " there's an additional byte set to 0) so we simply need to count until we read 0.

    while(*ppm && (len < (size-1))){                    // Copy ppm string into buffer, but only while it fits. Subtract one, reserved for NULL termination.
        text[len++] = *ppm++;
    }
    text[len] = 0;                                      // ALWAYS finish the string (NULL character) or you'll run into HUGE issues, most functions rely on this null char to detect string end.
}

« Last Edit: December 02, 2023, 10:15:33 pm by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 
The following users thanked this post: Veketti

Online IanB

  • Super Contributor
  • ***
  • Posts: 12437
  • Country: us
Re: C pointer confusion on char arrays
« Reply #6 on: December 02, 2023, 09:54:31 pm »
DavidAlfa originally highlighted an important thing above, which is that you should always pass in the length of a buffer to a function, so the function knows the size of the thing it has to work with. Furthermore, the function should always check that the length is not exceeded, to avoid buffer overruns.

(DavidAlfa's originally quoted code was incomplete, but it might be fixed by now, or it might not have the length of the buffer as a function argument anymore.)
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6305
  • Country: es
Re: C pointer confusion on char arrays
« Reply #7 on: December 02, 2023, 10:10:45 pm »
Yeah, like always I messed up at some point and corrected it later. I was posting both examples, decided to clean it up and keep only the proper code... pasted part of old code (Copy & Paste task failed) and noticed when it was gone.
I must be the member with the Guinness World Records in edited messages  ::).
« Last Edit: December 02, 2023, 10:13:43 pm by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline radiolistener

  • Super Contributor
  • ***
  • Posts: 4068
  • Country: ua
Re: C pointer confusion on char arrays
« Reply #8 on: December 02, 2023, 11:29:41 pm »
Dear All,

I'm bit confused on warnings regarding pointers and char arrays. When calling function and having "&" for the char array, it gives error "incompatible pointer type. If I leave this ampersand out, no warning. So should it be left out for char arrays?

Code: [Select]
unsigned char text[30] = "Hello";

int main(void)
{
ManipulateString(&text); // Warning: incompatible pointer type
}


void ManipulateString(unsigned char* text[])
{
// do something
}

array name is a pointer. So variable text in your code has type unsigned char*. When you use &text it returns unsigned char**, but your function expects unsigned char* which is different type, this is why there is error...

This works exactly the same for C, C++ and C#. C# has a little different syntax for array definition, but array variable still can be used as a pointer, the same as in C and C++. For local array you can pass array as pointer directly, but if array is declared non local you're needs to pin the memory allocated for array because it is allocated in managed memory and can be moved during defragmentation, in such case pointer for non pinned array will become invalid and accessing it can cause access violation exception or can corrupt process memory.
« Last Edit: December 02, 2023, 11:40:43 pm by radiolistener »
 

Online ejeffrey

  • Super Contributor
  • ***
  • Posts: 3968
  • Country: us
Re: C pointer confusion on char arrays
« Reply #9 on: December 02, 2023, 11:39:26 pm »
Dear All,

I'm bit confused on warnings regarding pointers and char arrays. When calling function and having "&" for the char array, it gives error "incompatible pointer type. If I leave this ampersand out, no warning. So should it be left out for char arrays?

Code: [Select]
unsigned char text[30] = "Hello";

int main(void)
{
ManipulateString(&text); // Warning: incompatible pointer type
}


void ManipulateString(unsigned char* text[])
{
// do something
}

array name is a pointer. So variable text in your code has type unsigned char*. When you use &text it returns unsigned char**, but your function expects unsigned char* which is different type, this is why there is error...

This works exactly the same for C, C++ and C#.

Nope.  Read more carefully.

First, while arrays automatically convert to pointers at function calls, they are not pointers.  So &text has the type char *.  Confusingly if you pass text to a function C implicitly takes the address of the first element and is also type char *. So, when passing function  arguments text and &text are exactly the same thing.

Instead of you look closely the function is actually expecting (char **) but it is spelled in the equivalent (char *text[]).
 

Online IanB

  • Super Contributor
  • ***
  • Posts: 12437
  • Country: us
Re: C pointer confusion on char arrays
« Reply #10 on: December 02, 2023, 11:45:57 pm »
So &text has the type char *.

This is not correct. While it is true that arrays are not pointers, the consequences go much deeper.

text is defined as an array of char of length 30, so &text is a pointer to an array of char of length 30. The type of &text is actually char (*)[30].

Code: [Select]
char text[30] = "hello";
typedef char (*Array30ptr)[30];  /* typedef improves readability for complex type declarations */
Array30ptr p = &text;
(*p)[15] = 'a';

On the other hand, &text[0] is a pointer to char, so you could write:

Code: [Select]
char text[30] = "hello";
char *q = &text[0];
q[16] = 'b';
« Last Edit: December 03, 2023, 01:46:43 am by IanB »
 

Online IanB

  • Super Contributor
  • ***
  • Posts: 12437
  • Country: us
Re: C pointer confusion on char arrays
« Reply #11 on: December 03, 2023, 01:43:36 am »
This works exactly the same for C, C++ and C#.
I don't know why you listed C# in there. C# is a different language entirely.

Quote
C# has a little different syntax for array definition, but array variable still can be used as a pointer, the same as in C and C++. For local array you can pass array as pointer directly, but if array is declared non local you're needs to pin the memory allocated for array because it is allocated in managed memory and can be moved during defragmentation, in such case pointer for non pinned array will become invalid and accessing it can cause access violation exception or can corrupt process memory.
And here you are just being silly. If you try to mess around with pointers like this, you are not writing C# anymore, and your code will be rejected by all competent reviewers. What you wrote has some technical truth to it, but it is not relevant to people learning C# as a programming language.

The only use for raw pointers and pinned memory in C# is for interop with native code, but this does not apply to people who are staying within the .NET CLR (as they should be when doing normal programming).
 

Offline VekettiTopic starter

  • Regular Contributor
  • *
  • Posts: 188
  • Country: fi
Re: C pointer confusion on char arrays
« Reply #12 on: December 03, 2023, 10:30:55 am »
Thank you all. Especially DavidAlfa, your example code works wonderfully. I previously received occasionally some groovy values, so I must have had some buffer overrun happening. I added loop to fill remaining space up to 16 characters with spaces to clear all the ghost characters from display (16x2 character display) if shown shorter value on display than previous value. Hope this doesn’t render the buffer overrun protection inoperable? Also changed the chars to unsigned to have the full 0-255 ascii codes available:
Code: [Select]
void ManipulateString(unsigned char * text, uint8_t size)
{
  unsigned char *ppm = "ppm"; // ppm string
unsigned char *s = text; // temporary pointer variable to use for own strlen
uint8_t len = 0;

while(*s++) len++; // This is basically strlen. A C string is always NULL ended (after "ppm " there's an additional byte set to 0) so we simply need to count until we read 0.

while(*ppm && (len < (size-1))) // Copy ppm string into buffer, but only while it fits. Subtract one, reserved for NULL termination.
{
text[len++] = *ppm++;
}
    while(len < 17)
    {
        text[len++] = ' '; // fill spaces to empty screen ghost characters from previous longer values
    }
text[len] = 0;
}

What I’m basically trying to make is CO meter for my home to monitor that I don’t close the flue damper too early on my wood burning fireplace. Eventually I’m planning to make many of these with zigbee or similar wireless capability to have unit on multiple rooms and then one display to monitor the values in bedrooms etc. However so far my STM32G050F6P6 with 32kB of memory is already >89% full and it is just showing the value on display and instruction. If I originally knew these STM32 need lots of memory for HAL I’d go with higher memory unit. I’ve got some G070CBT6 with 128kB of flash so hopefully that is enough.. I’m not that capable to do the programming without HAL so I guess I don’t have other choice. In contrast with PIC16F1847 I never ran out of its 14kB memory and had much more complicated code.

For the CO module I’m using Winsen ZE07-CO –module. One thing I’d also like to ask, this is bit off from the original pointer topic, but hope it’s ok. Datasheet of that unit tells to get the concentration value you need to: Gas concentration value = (High Byte*256+Low Byte) x 0.1. I found one example where this was done by:
Code: [Select]
value = (float)((float)(answer_data[2]<<8 | answer_data[3]))/10;Bitwise shift is clear, but could someone explain the bitwise OR |? Datasheet is telling to add the low byte but in this example used bitwise OR operator. Obviously it works, but I just don’t understand why.

Thank you very much!
 

Offline VekettiTopic starter

  • Regular Contributor
  • *
  • Posts: 188
  • Country: fi
Re: C pointer confusion on char arrays
« Reply #13 on: December 03, 2023, 10:43:56 am »
Picture of the current breadboard setup. On background "real" residential CO meter. Its minimum value that it shows is 10ppm so I think there is some extra marginal compared to this "higher end" ZE-07..
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6305
  • Country: es
Re: C pointer confusion on char arrays
« Reply #14 on: December 03, 2023, 01:21:14 pm »
However so far my STM32G050F6P6 with 32kB of memory is already >89% full and it is just showing the value on display and instruction.
Are you enabling compiler optimizations for that STM32G050F6P6? Ensure to set it to Os (Optimize for size).


Bitwise shift is clear, but could someone explain the bitwise OR |
1
In this case it's the same result, you shifted the value 8 bits to the left, so the lower byte is empty, nothing there to cause a carry.
Ex.:
1000 + 1=1001
1000 | 1 = 1001.
« Last Edit: December 03, 2023, 01:37:05 pm by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 
The following users thanked this post: Veketti

Offline VekettiTopic starter

  • Regular Contributor
  • *
  • Posts: 188
  • Country: fi
Re: C pointer confusion on char arrays
« Reply #15 on: December 03, 2023, 02:17:06 pm »
Are you enabling compiler optimizations for that STM32G050F6P6? Ensure to set it to Os (Optimize for size).
Oh my. Didn't know about that. Enabled it and now it is 68%. Wohoo. Makes me wonder why it isn't enabled as default?

In this case it's the same result, you shifted the value 8 bits to the left, so the lower byte is empty, nothing there to cause a carry.
Ex.:
1000 + 1=1001
1000 | 1 = 1001.
Indeed. I couldn't get my head around it that 11 | 01 is still three not four, but the shift made the differences.

Sorry to ask again, but was it so that the added space filling didn't mess that buffer overrun protection?
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6305
  • Country: es
Re: C pointer confusion on char arrays
« Reply #16 on: December 03, 2023, 02:37:22 pm »
Because it might cause problems if you don't code well. Mainly in interrupts and such.
Check where your space is going in the build analyzer.
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6305
  • Country: es
Re: C pointer confusion on char arrays
« Reply #17 on: December 03, 2023, 02:42:30 pm »
Code: [Select]
    while(len < 17 && (len < (size-1))) // This ensures no buffer overrun happens
    {
        text[len++] = ' '; // fill spaces to empty screen ghost characters from previous longer values
    }

But anyways, if you know the buffer is larger than 17, and any string you append won't surpass it, it can be omitted.
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline radiolistener

  • Super Contributor
  • ***
  • Posts: 4068
  • Country: ua
Re: C pointer confusion on char arrays
« Reply #18 on: December 03, 2023, 03:10:34 pm »
And here you are just being silly. If you try to mess around with pointers like this, you are not writing C# anymore, and your code will be rejected by all competent reviewers. What you wrote has some technical truth to it, but it is not relevant to people learning C# as a programming language.

Pointers is a part of C# language and there is nothing wrong with it. It allows to write clean and fast code, especially when you're doing marshaling with native code. It is unsafe, because it is allows to do direct memory access, but if you're know what you're doing you can use it to write clean and fast code. The same you're needs to know what you're doing when you dealing with C/C++ pointers. But with C# it is a little bit more complicated because managed memory can be defragmented, so it needs to be careful when you're passing pointer to a managed memory to unmanaged code.

For example I wrote game engine with using direct OpenGL/OpenAL calls in pure C# and it works great, surprisingly more fast and more stable than existing engines written in C/C++. And it don't needs to recompile, I can run the same executable on Windows, Linux and macOS with no issue. It will be impossible with no using pointers.
« Last Edit: December 03, 2023, 03:25:57 pm by radiolistener »
 

Offline Kosmic

  • Super Contributor
  • ***
  • Posts: 2554
  • Country: ca
Re: C pointer confusion on char arrays
« Reply #19 on: December 03, 2023, 03:21:58 pm »
And here you are just being silly. If you try to mess around with pointers like this, you are not writing C# anymore, and your code will be rejected by all competent reviewers. What you wrote has some technical truth to it, but it is not relevant to people learning C# as a programming language.

Pointers is a part of C# language and there is nothing wrong with it. It allows to write clean and fast code, especially when you're doing marshaling with native code. It is unsafe, because it is allows to do direct memory access, but if you're know what you're doing you can use it to write clean and fast code. The same you're needs to know what you're doing when you dealing with C/C++ pointers.

For example I wrote game engine with using direct OpenGL/OpenAL calls in pure C# and it works great, surprisingly more fast and more stable than existing engines written in C/C++. It will be impossible with no using pointers.

It's not because "you can do it" and "it works" that it's necessarily a good idea  :-\

unsafe operation in C# are the exception and are normally never used. If your code is full of it, you are not using C# correctly or you are using the wrong programming language for what you are trying to achieve.
 

Offline radiolistener

  • Super Contributor
  • ***
  • Posts: 4068
  • Country: ua
Re: C pointer confusion on char arrays
« Reply #20 on: December 03, 2023, 03:32:14 pm »
unsafe operation in C# are the exception and are normally never used. If your code is full of it, you are not using C# correctly or you are using the wrong programming language for what you are trying to achieve.

I'm writing in C# from 2004 and worked on a very large enterprise projects. So, don't tell me what I'm using correctly and what is not...  At about 2006 I also had thoughts like your due to lack of knowledge... but since then a lot of water has passed under the bridge and I learned a lot of new things and saw a lot of different code.

Unsafe code is just a thing which needs to be used properly. This is true that this is complicated part and novice cannot use it properly. But if you try to avoid it where it is required you will get bullshit code which works slow and hard to read.
« Last Edit: December 03, 2023, 03:39:20 pm by radiolistener »
 

Offline Kosmic

  • Super Contributor
  • ***
  • Posts: 2554
  • Country: ca
Re: C pointer confusion on char arrays
« Reply #21 on: December 03, 2023, 03:37:08 pm »
unsafe operation in C# are the exception and are normally never used. If your code is full of it, you are not using C# correctly or you are using the wrong programming language for what you are trying to achieve.

I'm writing in C# from 2004 and worked on a very large enterprise projects. So, don't tell me what I'm using correctly and what is not...  At about 2006 I also had thoughts like your due to lack of knowledge...

Hehe, I have a master degree and more than 20 years exp as a professional programmer mostly in C++ but also C and C#. Trust me I don't lack knowledge  ;)
 

Offline Kosmic

  • Super Contributor
  • ***
  • Posts: 2554
  • Country: ca
Re: C pointer confusion on char arrays
« Reply #22 on: December 03, 2023, 03:54:56 pm »
unsafe operation in C# are the exception and are normally never used. If your code is full of it, you are not using C# correctly or you are using the wrong programming language for what you are trying to achieve.
Unsafe code is just a thing which needs to be used properly. This is true that this is complicated part and novice cannot use it properly. But if you try to avoid it where it is required you will get bullshit code which works slow and hard to read.

Why not simply using C++ then ?
 

Offline radiolistener

  • Super Contributor
  • ***
  • Posts: 4068
  • Country: ua
Re: C pointer confusion on char arrays
« Reply #23 on: December 03, 2023, 04:13:06 pm »
Hehe, I have a master degree and more than 20 years exp as a professional programmer mostly in C++ but also C and C#. Trust me I don't lack knowledge  ;)

if you wanted to impress me with this, your attempt is failed. I got master degree with honors in Computer Science (software development of automation systems) 20 years ago, before that I also get bachelor degree in computer electronics. I wrote first C program at about 1992, and learned C++ at about 1994. Most of the time I worked as software development engineer in medical devices industry for a company which was in a top 5 of fortune 500 list.

As you probably understand this is much more strict than usual programming, because it requires additional knowledge of software development lifecycle and medical standards certification (ISO13485 etc) with regular examination to be allowed to work on medical devices projects. If you know requirements for medical devices and software systems used in cardiology surgery and cardiopulmonary resuscitation, then you can understand why it uses so strong requirements for development process and this is what I worked on. And what? ;)
« Last Edit: December 03, 2023, 04:15:46 pm by radiolistener »
 

Offline radiolistener

  • Super Contributor
  • ***
  • Posts: 4068
  • Country: ua
Re: C pointer confusion on char arrays
« Reply #24 on: December 03, 2023, 04:26:35 pm »
Why not simply using C++ then ?

C++ is more unsafe than C# with unsafe code, it's more hard to debug and perform code analysis. Technically yes, you can do all things in C++ more effective, but in practice it will be more hard than in C#, because it will be more easy to do some mistake in C++ and more hard to find/detect it.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf