looping over an array of undefined length in c - c

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?

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.

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)

Related

Is it possible to assign data to this "static array" in C using for-loop?

There is a line of code inside a method similar to:
static char data[] = "123456789";
I want to fill the above data array with a million characters not just nine.
But since it is tedious to type it, I want to do that in for loop.
Is that possible to do it keeping it as "static char data[]"?
edit:
static char data[1000000];
for(int i=0; i<1000000; i++)
{
data[i] = 1;
}
There are multiple ways to achieve this in C:
you can declare the global static array as uninitialized, write an initialization function and call this function at the beginning of the program. Unlike C++, C does not have a standard way to invoke such an initialisation function at program startup time, yet some compilers might provide an extension for this.
static char data[1000000];
void init_data(void) {
//the loop below will generate the same code as
//memset(data, 1, sizeof data);
for (int i = 0; i < 1000000; i++) {
data[i] = 1;
}
}
int main() {
init_data();
...
}
you can change your program logic so the array can be initialized to 0 instead of 1. This will remove the need for an initialization function and might simplify the code and reduce the executable size.
you can create the initializer for the array using an external program and include its output:
static char data[1000000] = {
#include "init_data.def"
};
you can initialize the array using macros
#define X10(s) s,s,s,s,s,s,s,s,s,s
#define X100(s) X10(s),X10(s),X10(s),X10(s),X10(s),X10(s),X10(s),X10(s),X10(s),X10(s)
#define X1000(s) X100(s),X100(s),X100(s),X100(s),X100(s),X100(s),X100(s),X100(s),X100(s),X100(s)
#define X10000(s) X1000(s),X1000(s),X1000(s),X1000(s),X1000(s),X1000(s),X1000(s),X1000(s),X1000(s),X1000(s)
#define X100000(s) X10000(s),X10000(s),X10000(s),X10000(s),X10000(s),X10000(s),X10000(s),X10000(s),X10000(s),X10000(s)
static char data[1000000] = {
X100000(1), X100000(1), X100000(1), X100000(1), X100000(1),
X100000(1), X100000(1), X100000(1), X100000(1), X100000(1),
};
Note however that this approach will be a stress test for both your compiler and readers of your code. Here are some timings:
clang: 1.867s
gcc: 5.575s
tcc: 0.690s
The last 2 solutions allow for data to be defined as a constant object.
Is that possible to do it keeping it as "static char data[]"?
No, you have to specify the size explicitly. If you wish to compile-time initialize the array rather than assigning to it in run-time with a for loop or memset, you can use tricks such as this.
Another option might be to use dynamic allocation with malloc instead, but then you have to assign everything in run-time.
You can define statically allocated arrays in various ways, incidentally, this has nothing to do with the static keyword, see this if you need more information about static variables. The following discussion won't have anything to do with that, hence I will be omitting your static keyword for simplicity.
An array declared as:
char data[] = "123456789";
is allocated in the stack in the compile time. Compiler can do that since the size of the array is implicitly given with the string "123456789" to be 10 characters, 9 for the data and +1 for the terminating null character.
char data[];
On the other hand, will not compile, and your compiler will complain about missing array sizes. As I said, since this declaration allocates the array in the compile time, your compiler wants to know how much to allocate.
char data[1000000];
This on the other hand will compile just fine. Since now the compiler knows how much to allocate. And you can assign elements as you did in a for loop:
for(int i=0; i<1000000; i++)
{
data[i] = 1;
}
Note:
An array of million chars has quite a respectable size, typically 1Mb, and may overflow your stack. Whether or not that it actually will depends on pretty much everything that it can depend on, but it certainly will rise some eyebrows even if your code works fine. And eventually, if you keep increasing the size you will end up overflowing your buffer.
If you have truly large arrays you need to work with, you can allocate them on the heap, i.e., in the wast empty oceans of your ram.
The part above hopefully should have answered your question. Below is simply an alternative way to assign a fixed value, such as your (1), to a char array, instead of using for loops. This is nothing but a more convenient way (and perhaps a better practice), you are free to ignore it if it causes confusion.
#include <string.h>
#define SIZE 100000
// Create the array, at this point filled with garbage.
static char data[SIZE];
int main( void )
{
// Initialise the array: assigns *integer 1* to each element.
memset( data, 1, sizeof data )
//^___ This single line is equivalent of:
// for ( int i = 0; i < SIZE; i++ )
// {
// data[i] = 1;
// }
.
.
.
return 0;
}

Turning array in main into a global, to later be altered by main?

I have two arrays of the alphabet in the following format:
const char plain[26] = {'a','b',....'y','z'} // this is the the full alphabet
const char crypt[26] = {'i','d',....'m','x'}; // this is the the alphabet scrambled
The order of the alphabet in both arrays can change depending on input. This change happens in the main function.
The purpose of this is to match the letters of the string to the second, like an encryption. I compare characters to array values. So it would kind of look like this (simplified)
text[3] = 'yes';
changed[3];
if(text[0] == plain[25]){ //would be done under a for loop so 25 would be a changing integer value
changed[0] = [crypt[25];
}
My code works under perfectly under the main function. I wanted to mention my purpose like this because I was having previous problems simply due to the type of array and formatting. And since the array is moved outside, I will probably/am running into those problems again.
Now I want to make the arrays global. The actual encryption happens in a function that does not take the arrays as a variable. But I want the function to have access to them.
Here's what it looks likes right now
const char plain[26];
const char crypt[26];
int maint(void){
const char plain[26] = {'a','b',....'y','z'} \\values get changed here
const char crypt[26] = {'i','d',....'m','x'} \\and here
While this provides no errors, I dont get an output, I believe the other functions are using a blank array instead of the changed one (if the change even worked).
I've tried different array types, I believe the issue is in initialization or giving the array values.
Edit: To clarify, the two arrays can be in any order. A text file will randomize the order can give it to me in the format:
b,r
m,o
l,s
...
...
...
Both cases the alphabet is randomized. Where the first column would correspond to the first array (plain), second would be to second array (crypt).
If there's a way to read by columns and store in the format
plain = 'bml...'; \\whole alphabet randomized
crypt = 'ros...'; \\whole alphabet randomized
That would also work.
The plain and crypt you have in main aren't the same as the global ones. Since you declare them again, they're new ones that are only visible in main. Thus you're not changing the global ones.
Instead, only declare them once globally and do assignment in the main function:
char plain[26];
int main(void) {
memcpy(plain, "abcdefghijklmnopqrstuvwxyz", 26); //values get changed here
return 0; // indicate successful program execution
}
Also note that there are some syntax errors in
const char plain[26] = {'a','b',....'y','z'} \\values get changed here
Comments start with //, not \\, and you need a ; after a statement. Also, the int main should return an int in C.
Of course, if you don't need to actually change the memory and only assign it to predefined sets of characters, you can do it like this:
const char *plain;
int main(void) {
plain = "abcdefghijklmnopqrstuvwxyz";
return 0;
}
This way you can still read from it with syntax like plain[5], but you can't assign to it with, say plain[5] = 'a';.
Remove "const char" before plain and crypt arrays in main function to see the actual issue.
“Const Char” before plan and crypt arrays actually declare two new local char array constants with same name. As “const” char array can only be initialized at the declaration time therefore initialization in main does not throw error because they are not same global conts arrays.
Instead of using const use Const pointer as suggested in below answer
Another way to look at it is that plain and crypt will both decay to pointers on access (subject to the exceptions in) C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3). So why not just use global pointers to begin with that can then be reassigned as needed throughout your code?
This provides the flexibility of assignment from (1) string literals; (2) constant arrays; or (3) from compound literal initializers. You can #define a constant for the size (number of characters) plain and crypt point to.
For example:
#include <stdio.h>
#define NC 3 /* number of chars (26 for you) */
const char *plain, *crypt; /* global pointers */
void prnchars (const char *arr)
{
for (int i = 0; i < NC; i++)
putchar (arr[i]);
putchar ('\n');
}
int main (void) {
plain = "abc"; /* assigning literals */
crypt = "def";
prnchars (plain);
prnchars (crypt);
crypt = "ghi"; /* reassign at will */
prnchars (crypt);
const char foo[] = "jkl"; /* constant arrays */
crypt = foo;
prnchars (crypt);
crypt = (const char[]){'m', 'n', 'o'}; /* compound literals */
prnchars (crypt);
return 0;
}
Example Use/Output
$ ./bin/global_ptr
abc
def
ghi
jkl
mno
It's just another way of looking at the problem.

use string with loop for in c

with this list of value:
char *icon[6] = {"icon0","icon1","icon2","icon3","icon4","icon5"};
char *ICON_FILE_PATH[6] = {"host0:img/200px/power-button-off.png","host0:img/200px/gamepad-console.png","host0:img/200px/dropbox-logo.png","host0:img/200px/open-folder.png","host0:img/200px/sitemap.png","host0:img/200px/settings.png"};
I need to get that:
#define ICON_FILE_PATH1 "host0:img/200px/power-button-off.png"
#define ICON_FILE_PATH2 "host0:img/200px/gamepad-console.png"
etc...
extern Orbis2dTexture *icon0;
extern Orbis2dTexture *icon0;
etc...
Orbis2dTexture *icon0 = NULL;
Orbis2dTexture *icon0 = NULL;
etc...
for each value of ICON_FILE_PATH.
I mean to use :
for (int i=0; i<=5; i++ )
{
#define ?????
extern ?????
Orbis2dTexture ????
}
But I don't know how do...
If you want strings change 'to ".
char *icon[6] = {"icon0","icon1","icon2","icon3","icon4","icon5"};
That sets up an array of pointers to char, initialised with the "readonly" pointers to string literals.
'icon0' is a (weird) multibyte character constant, not a multi character constant which could serve as a string.
The rest of the shown code is even more weird. I skip discussing it here.
Have a look at the comments.
Allow me to recommend starting with HelloWorlds and tutorials which provide you with known good code and then do little steps, always verified by testing, to upgrade the functionality of your program and your knowledge in parallel.

C - fprintf() & printf() deleting array element memory

I fairly new to C Programming, but fprintf() & printf() is behaving strangely and I'm so confused on why--I need some help understanding and diagnosing this issue.
fprintf() Deleting Element of Array
First off, I'm passing in a populated malloc allocated four element char** array into a simple function that will write to a file, everything in the array appears normal and all four elements contain the correct data. The function call in main() looks like this. My array in question is header.
Note: I had to cast this normal (char** array) as a constant in this function parameter, due to the function header parameter. Our professor gave us the header file and we cannot change anything in them.
pgmWrite((const char**) header, (const int**) matrix,
rowPixels, colPixels, outFile);
Next, stopping debugger just before it executes the fprintf() & printf() functions, screenshot showing the array is still populated with my 4 elements.
pgmWrite() - Showing array is still fine
Observe the 4th element of the array after execution of fprintf().
After fprintf() executes, element 3 memory is wiped out.
When run, printf() executes the printing of the array exactly what is shown in the debugger, ending at the 3rd element. Often printing nothing in that spot or in rare cases garbage characters. The behavior of printf() is exactly the same as how fprintf() is working as well.
I'm at a loss here guys, please help me understand what I'm doing wrong. I can only provide these two screenshots, based on me being a new member. I'll try to provide as much information as possible. Thank you. Here is a simplified version of my program. Keep in mind, the professor gave us the function declarations and told us we cannot change them. So, I have to work with what I have here. Also, since this is fileIO, you need to find a *.pgm file to test this.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define rowsInHeader 4
#define maxSizeHeadRow 200
int ** pgmRead( char **header, int *numRows, int *numCols, FILE *in ){
// INITIALIZING
char *headArr[rowsInHeader][maxSizeHeadRow];
char buffer[100];
int r = 0;
fpos_t pos;
// CREATE: Header
while (r < 4){
// IF: Row in pgm file header lists the dimensions of matrix
if (r == 2){
// CURSOR: Saving pointer location in file (see notes in header for method reference)
fgetpos(in, &pos);
// ASSIGN: Dereference column and row pointers from file
fscanf(in, "%d %d", numCols, numRows);
// CURSOR: Moving back to saved pointer location (see notes in header for method reference)
fsetpos(in, &pos);
}
// ASSIGN: Copying header row into array
fgets(buffer, maxSizeHeadRow, in);
strcpy((char*)headArr[r], buffer);
// POINTER: Reference pointer to headArr[]
header[r] = (char*)headArr[r];
// TRAVERSE: To next row in file
r++;
}
// NOTE: Placeholder for return type
return 0;
}
int pgmWrite( const char **header, const int **pixels, int numRows, int numCols, FILE *out ){
// INITIALIZING
int i = 0;
// WRITE: Header
for (i = 0; i < rowsInHeader; i++){
fprintf(out, "%s", header[i]);
printf("%s", header[i]);
}
return 0;
}
int main(int argc, char *argv[]){
char **header = (char**)malloc(rowsInHeader * sizeof(char));
FILE *inFile = fopen("smallFile.pgm", "r");
FILE *outFile = fopen("TestPicture.ascii.pgm", "w");;
int rowPixels = 0;
int colPixels = 0;
int **matrix = NULL;
// READ & WRITE
matrix = pgmRead(header, &rowPixels, &colPixels, inFile);
pgmWrite((const char**)header, (const int**)matrix, rowPixels, colPixels, outFile);
// FINALIZING
fclose(inFile);
free(header);
return 0;
}
You are not allocating your array correctly. This line:
char **header = (char**)malloc(rowsInHeader * sizeof(char));
makes header point to an uninitialized region of memory , size 4 bytes.
Then inside your PGM function you write:
header[r] = (char*)headArr[r];
The code header[r] means to access the r'th pointer stored in the space pointed to by headArr. But since that space is only 4 bytes big, you're actually writing off into the wild blue yonder.
Also, (char *)headArr[r] is a mistake. If you did not use the cast, your compiler would have warned you about this mistake. You should avoid using casts in your code, especially using them to make warnings go away. You're saying to the compiler "Ssh, I know what I'm doing" when in fact you don't know what you are doing.
The entire approach with headArr is flawed from the start: even if you had actually written the right code to implement what you were trying, you'd be returning pointers into space which is deallocated when the function returns.
Basically the whole pgmRead function is a complete mess and it'd be easier to start from scratch. But this time, think carefully about when and where you are allocating memory, and what the types are of your expressions, and don't use casts. Let the pgmRead function do all the allocation.
(Unfortunately, based on your description it looks like you will have to use your casts to call the pgmWrite function since that has a mistake in its signature. const int ** should be const int * const *, and similarly for const char **. I'd recommend to actually change pgmWrite's signature accordingly, get your program working, and then once everything is good, then go back to the broken version that you are forced to use.)
Reading C FAQ - arrays and pointers might be useful too.

C - Creating and using an struct array? error: expected identifier or '(' before '[' token

So I am trying to build and use a struct array in C, and I am encountering a few errors of which I cannot resolve. The code that I have is:
int numWords = 10;
typedef struct
{
char* word;
int count;
} wordsCount;
wordsCount words[numWords];
words[0].word = "Hello";
words[0].count = 1;
First of all, when using the gcc compiler in Unix, I receive an warning, when compiling with the -Wall -pedantic -ansi flags, which reads warning: ISO C90 forbids variable length array 'words' [-Wvla]. And for the last two lines of my code snippet, I receive the error: error: expected identifier or '(' before '[' token.
Could anybody tell me why I am getting these errors? I've Googled many different typedef and struct examples, and mine mirrors that of those examples.
EDIT:
Thank you all for the suggestions. I decided to edit my post instead of responding to each individual comment to provide some clarification of my question. So, I now understand that you can't use variable length arrays in C. I can't officially accept any of the provided answers because my problem still exists, so a clearer explanation of what I am trying to do is warranted.
I am creating a program which counts the occurrences of each word in a text file and prints it out in ASCII order. For example, if the text file contains the following text: "Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo" is a grammatically correct sentence., the output of the program shall be:
Buffalo - 3
a - 1
buffalo - 5
correct - 1
sentence - 1.
The words themselves are already stored into an array. So I want to create an array of structs that contain both the word and the count. I've revised my program to account for dynamically allocated memory. My updated code is:
typedef struct
{
char* word;
int count;
} wordsCount;
wordsCount** words = malloc(sizeof(*words) * numWords);
words[0]->word = "Hello";
words[0]->count = 2;
printf("%s - %d\n", words[0]->word, words[0]->count);
*Note that numWords is an integer that changes according to how large the text file is.
It compiles fine; however, I receive a seg fault at the first assignment statement words[0]->word = "Hello";.
Am I wrong to assume that I can create a pointer to a pointer to structs? I thought the `->' operator does the deference of the struct pointer, and then point to the member "word." I do not understand why I am seg faulting. Any help would be appreciated. If making this edit warrants a new thread, please let me know so I can move it. Thanks.
EDIT 2
I figured out the problem - I was pointer-happy and used way too many pointers to do what I want. I changed wordsCount** words = malloc(sizeof(*words) * numWords); to wordsCount* words = malloc(sizeof(*words) * numWords);. And then I realized I was doing necessary dereferencing when I did words[0]->word = "Hello";, so I changed it to words[0].word = "Hello";, and it works perfectly. Thanks for the help, guys. I'm not sure how to close a thread, or if I should post an answer to my own question? But this thread is now closed.
#define NUM_WORDS 10
typedef struct
{
char* word;
int count;
} wordsCount;
wordsCount words[NUM_WORDS];
This will sufficiently allocate the memory you will need in order to start assigning values.
The compiler needs to know how big the 'words' array should be, so when it comes across your array initialization, it expects to find a size between the brackets. But it finds the 'numWords' variable instead and it can't use that. The preprocessor will not replace 'numWords' with '10'. It will do so when you change this
int numWords = 10;
to this
#define numWords 10
That should work. The preprocessor will then replace every instance of the word 'numWords' in your code with '10', so that the array initialization will read:
wordsCount words[10];
There are two main problems.
The first, ably identified by the other answers, is that you can't use a VLA at global scope. Since numWords is an int variable, it is not a constant and array dimensions at file scope must be constants.
I'd recommend:
enum { numWords = 10 };
See also static const vs #define in C.
The second problem is that you are writing assignments at global scope, and that is not allowed either. You can provide an initializer, though:
enum { numWords = 10 };
typedef struct
{
char* word;
int count;
} wordsCount;
static wordsCount words[numWords] =
{
{ "Hello", 1 },
};
You wouldn't want to let code outside this file access your variables, would you?

Resources