0

so I'm trying to iterate over a char array in c. The Array is defined in a header file like this.

char const SEQUENCE[] PROGMEM = "\MdTqZWYzVf5E661OAd4r7ylINBLNEAzO... the array is well over 1 thousand characters in length.

next I've been told to use the extern key word to bring the array into my main.c file. this is how I've done that. Not sure if this is totally correct.

extern char const SEQUENCE[];

I've tried to loop over the array and pring each individual value like this.

for (uint8_t I = 0; I < 64; I++) { printf("%c ", SEQUENCE[I]); }

but I got this as an output.

␏ ␀ ␀ ␀ ␀ ␀ ␀ ..

I expected something like. M d T q ...

can anyone tell me what is going wrong here?

Sam
  • 1
  • Why not just `#include` the header in your "main.c"? Then you can just loop through the string/array until you find the `nul` terminator. – Adrian Mole Nov 04 '22 at 11:58
  • 2
    Does that `PROGMEM` keyword mean something special? – Steve Summit Nov 04 '22 at 12:09
  • 2
    Edit the question to provide a [mre]. – Eric Postpischil Nov 04 '22 at 12:12
  • 3
    You've got at least two unrelated problems: (1) type `uint8_t` is never going to be able to iterate over thousands of characters; (2) `\M` (right at the beginning of your `SEQUENCE` string) is not a legal character escape sequence. But other than that, your code worked fine for me, and printed `M d T q Z W Y z V f 5 …` as expected. So whatever is causing it to print those NULLs must involve some other factor of your code or your environment, that we can't see. – Steve Summit Nov 04 '22 at 12:13
  • 2
    This: `char const SEQUENCE[] PROGMEM = "\MdTqZWYz..";` does not compile. I cannot think of any definition for `PROGMEM` that would allow it to be in that position of a declaration. Changing it to `char const SEQUENCE[PROGMEM] = "\MdTqZWYz..";` would be legal, but not recommended unless value of `PROGMEM` is guaranteed to be larger than the number of array elements. – ryyker Nov 04 '22 at 12:33
  • @SteveSummit - What code did you run that worked fine? the declaration as is will not compile for me. Did you just remove that part? – ryyker Nov 04 '22 at 12:38
  • 1
    @ryyker It's not unusual to hide system-specific storage classes or other qualifiers behind macros. I assume that's what this is (but the OP hasn't answered my question about it yet). So I just added `#define PROGMEM`. (Which was admittedly silly, because yes, I could more easily have just removed the `PROGMEM` part.) (Also, yes, you're right, the positioning is weird.) – Steve Summit Nov 04 '22 at 12:41
  • 1
    `PROGMEM` is often used by Harvard CPU embedded systems (like AVR), where you run into problems accessing data memory directly from program memory unless it is loaded into RAM first. It will tell the compiler to link the data to flash and then as needed implicitly insert various hoops and loops in the program, when it wishes to access that data. It's senseless to use it on a PC. – Lundin Nov 04 '22 at 14:26
  • 1
    Based on what @Lundin is saying, my pure guess (without any experience with microcontrollers) would be to do: `extern char const SEQUENCE[];` -> `extern char const SEQUENCE[] PROGMEM;` Check the documantetion for PROGMEM in the documentation of your microcontroller. – HAL9000 Nov 04 '22 at 14:52

2 Answers2

1

As mentioned in comments, there are some immediately noticeable problems with what you have shown...

  • type uint8_t is clearly one byte wide, yielding a maximum of 256 iterations ( 0 - 255 ) before its value begins to repeat back to zero, thus printing out the first 256 characters again, and again,.... This will not satisfy your stated buffer size of "well over 1 thousand characters".
  • The declaration extern char const SEQUENCE[]; (I assume was to be in a header file.) although legal, is not usable for any discernible way within the stated objectives. It is an empty array, and must remain that way until the end of its life at program exit.

It is difficult to know for certain exactly what arrangement satisfies the requirements, because the requirements are not clearly stated mentioning only a header file declaration using extern and const to create a buffer, and that the buffer should then be brought out to be used in the main() function. The following interpretation, although based on some assumptions does these things, and allows the buffer to be output:

in something.h

const char buf[] = "\MdTqZWYzVf5E661OAd4r7ylINBLNEAzO...";//smaller for illustration
#define PROGMEM sizeof(buf) //to be used when indexing through array
extern const char SEQUENCE[] = "\MdTqZWYzVf5E661OAd4r7ylINBLNEAzO..."; 

In main.c

#include "something.h"
int main(void)
{
    for(int i = 0; i < PROGMEM; i++)//note use of int
    {
        //extern usage
        printf("%c", SEQUENCE[i]);  
    }
    return 0;
}

Note: The extern keyword is used to effect scope and duration, making a fuction/variable visible throughout a program. In this example, there is no compelling reason to use the extern keyword other than it is a stated requirement. The buffer SEQUENCE created in the header file without extern scope is completely sufficient here. It may be interesting for you to review others thoughts on how and when the extern keyword should be applied.

ryyker
  • 22,849
  • 3
  • 43
  • 87
-1

header:

#ifndef INCLUDE_headername_H
#define INCLUDE_headername_H
...
extern const char* SEQUENCE;
...
#endif

c

#include "headername.h"

const char* SEQUENCE = "mystring..."

int main() {
    for (int i = 0; SEQUENCE[i]; i++) {
        ...
    }
}

This works, because SEQUENCE is a string, and at the end (and only at the end) will be a null-terminater. This does not work, if you place one by yourself (with \0)

Tenobaal
  • 637
  • 1
  • 16