use string with loop for in c - 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.

Related

looping over an array of undefined length in 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)

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.

concatenate variable onto another variable

const char *SITE_NAME = "test";
char SITE_ROOT[19];
sprintf (SITE_ROOT, "/var/www/html/%s", SITE_NAME);
I can't figure out why I'm getting an error of:
error: expected ‘)’ before string constant
Basically I just want to concatenate the variable SITE_NAME onto SITE_ROOT. The error is on the sprintf line. Any ideas?
UPDATE: So the code works if it is inside main(). I had it outside of main() so that I could use those variables inside of functions.
The error looks like it might not be shown in the code but the sprintf should be:
sprintf (SITE_ROOT, "/var/www/html/%s", SITE_NAME);
EDIT:
Here is my complete test code if that helps at all:
#include <string.h>
#include <stdio.h>
int main()
{
const char *SITE_NAME = "test";
char SITE_ROOT[19];
sprintf (SITE_ROOT, "/var/www/html/%s", SITE_NAME);
printf( "%s\n", SITE_ROOT ) ;
return 0 ;
}
As has been pointed out, the direct problem is that you're trying to call sprintf from outside a function.
You mentioned that you are setting the strings this way because you're using SITE_NAME by itself in addition to concatenating it with the path and you want to only have to change it in one place. This is a good goal, known in some circles as "don't repeat yourself" (often abbreviated DRY). However, even if the code worked (say, because you moved the sprintf call into main), you haven't really achieved your goal due to the following line:
char SITE_ROOT[19];
You are declaring a fixed length array exactly big enough to hold "/var/www/html/test", which is just asking for a buffer overflow. When you change SITE_NAME from "test" to, for example, "someRealSiteName", you'll very probably overwrite something else when you concatenate, causing unpredictable results. So you have to manually recalculate the length of the final string and update the array size (which would be easy to get wrong, say by forgetting to add 1 for the null terminator) every time you change SITE_NAME.
You could, of course, limit the length of SITE_NAME and size SITE_ROOT to hold the longest possible path, but it'd be an artificial limit and you might end up wasting space. Furthermore, you'd still have to verify the length isn't exceeded at run-time (or use a function that will ignore extra characters).
Instead, you could dynamically set the size of SITE_ROOT like so:
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
const char SITE_PATH[] = "/var/www/html/";
const char SITE_NAME[] = "someRealSiteName";
char *SITE_ROOT = NULL; // just making this explicit, would be set to 0 anyway
int main(void)
{
size_t siteRootLength = strlen(SITE_PATH) + strlen(SITE_NAME);
SITE_ROOT = malloc(siteRootLength + 1); //don't forget to account for the terminating '\0'
strcpy(SITE_ROOT, SITE_PATH);
strcat(SITE_ROOT, SITE_NAME);
printf("%s\n", SITE_NAME):
printf("%s\n", SITE_PATH):
printf("%s\n", SITE_ROOT):
return 0;
}
This solution is okay, but has some drawbacks:
SITE_ROOT can't be a const pointer , so both the string and the pointer itself could be accidentally changed
Site path and name will each be in memory twice (though it sounds like you're okay with that)
Concatenation is being done at run-time when it could be done at compile-time
Code is longer and more complex than necessary for such a simple task
Risk that SITE_ROOT is used before it has the correct value (or is even a valid pointer/string!) in some other initialization code or another thread.
I feel something like the following is better:
#include <stdio.h>
#define SITE_PATH_MACRO "/var/www/html/"
#define SITE_NAME_MACRO "someRealSiteName"
// the preprocessor will merge the two string literals into one
#define SITE_ROOT_MACRO SITE_PATH_MACRO SITE_NAME_MACRO
// you could do without some or all of these if you don't need them
// (or are willing to use the macros directly)
const char SITE_PATH[] = SITE_PATH_MACRO;
const char SITE_NAME[] = SITE_NAME_MACRO;
const char SITE_ROOT[] = SITE_ROOT_MACRO;
int main(void)
{
printf("%s\n", SITE_NAME);
printf("%s\n", SITE_PATH);
printf("%s\n", SITE_ROOT);
return 0;
}
Since this is a pretty straightforward case, you can simply initialize the string and then concatenate onto it. You might want to add checks to ensure you don't go beyond you string's boundaries though.
strcpy(SITE_ROOT, "/var/www/html/");
strcat(SITE_ROOT, SITE_NAME);

Assign a string created in a function to a typedef structure array created in main

Alright. So I have this program in C where I take a string with arguments and values (Such as: "GO 45 STOP 15"). The goal is to parse the string and place the argument with its corresponding value into a typedef structure to work with later on.
This is what my structure looks like:
typedef struct {
char* keyword;
double value;
} parameter;
Here are some copies of my code that I am having issues with.
Both main() and initParams() are in the same file and therefore both have access to the same #defines...
main():
#include <stdio.h>
#include <stdlib.h>
#include "findArgs.h"
#define STR0_SIZE 80
#define LIST_SIZE 4
#define MAX_PARAMS 15
void main(){
int i;
char str0[STR0_SIZE] = "LEFT 45 GO 686 GO 34.3 STOP 56 RIGHT 26"; //Input String
char* wordList[LIST_SIZE]={"GO", "STOP", "LEFT", "RIGHT"};
int num_arg = 0; //Number of arguements in str0 (each space denotes the end of an arg)
parameter* param;
initParams(param);
replaceSpaces(str0, &num_arg);
findWords(param, str0, num_arg);
}
initParams:
void initParams(parameter* param){
int ctr0, ctr1;
param = (parameter*) malloc(MAX_PARAMS * sizeof(parameter));
printf("\n%i\n", sizeof(parameter));
for(ctr0=0;ctr0<MAX_PARAMS;ctr0++){
param[ctr0].keyword = "";
param[ctr0].value = 0;
}
}
ok some quick explainations. initParams is for allocating the memory for each of my parameters. I am assuming that I will not have any idea how many parameters will be included in the string and plan on determining the number in the string later in the program. I do know that I will not accept more than parameters in the string.
After allocating the memory, I loop through each one and initialize each value to either an empty string or 0. (I do realize this is probably unnecessary, however I have done this as part of my code troubleshooting.
Continuing on, replaceSpaces() simply loops through the string and replaces each occurrence of ' ' with a '\0'. It also counts the number of arguements present in the string so that I know how many new strings I have just created by adding null terminators.
Now the tricky part in which I am having difficulty.
#define MAX_ARG_LENGTH 20
void findWords(parameter* param, char* str0, int num_arg){
parameter temp[countWords(str0, num_arg)];
int i;
int ctr0,ctr1, ctr2=0;
int word=0; //flag
char tempStr[MAX_ARG_LENGTH]="";
char* c0 = str0;
for(ctr0=0; ctr0<num_arg; ctr0++){
word=0;
ctr1=0;
if(((*c0 > 'a') && (*c0 <'z')) || ((*c0 > 'A') && (*c0 <'Z'))){
word=1;
tempStr[ctr1]=*c0;
ctr1++;
}
while(*c0 != '\0'){
c0++;
if(word)
tempStr[ctr1++] = *c0;
printf("\ntempStr: '%s'\n", tempStr);
}
if(word){
param[ctr2].keyword = tempStr;
printf("%s\n", param[ctr2].keyword);
ctr2++;
}
c0++;
}
for(i=0; i<num_arg/2;i++){
printf("'%s'\n", param[i].keyword);
printf("'%g'\n", param[i].value);
}
}
This function works properly at finding each word in the string and storing it in tempStr. My issue is with assigning it to my parameter array back in my main(). I have tried assigning them to a temp array of parameters and then setting "param" equal to the temp array. However due to the fact that param is a pointer, when I assign it a local location, after the function is finished, the memory is freed and lost. Enter my idea to use malloc to predefine memory for them and assign it after.
This is my current output when I compile and run the code. I added comments to clarify
16 //sizeof(parameter)
5 //Number of words in str0
LEFT
GO
GO
STOP
RIGHT
'RIGHT' //Things in single quotes are prints from the array of parameters
'8.05316e-315'
'RIGHT'
'0'
'RIGHT'
'8.04051e-315'
'RIGHT'
'0'
'RIGHT'
'0'
MAIN: //I printed these in main using the same for loop seen in findWord()
'▒▒'
'8.05316e-315'
'▒▒'
'0'
'▒▒'
'8.04051e-315'
'▒▒'
'0'
'▒▒'
'0'
If anyone can help me properly assign the contents of tempStr to a parameter in my array declared in main I would be greatly appreciative. Please Let me know if you need any more information.
THANK YOU ALL!! I GOT IT!!!
Rather than make "tempStr" I just assgned the characters directly to the param[index].keyword. It worked like a charm
Thank you guys very much! I had read many different Qs and As here before but this was my first time posting. I am very excited with how quickly you guys were able to reply.
Thanks again!
~Nick
I think you are misunderstanding what param[ctr2].keyword = tempStr; does It does not copy the string in tempstr to keyword it just makes keyword point to tempstr, which means all the keywords will point to the tempStr variable and will be invalid if you access it outside this function.
What you want to do is to make
char* keyword;
into
char keyword[MAX_ARG_LENGTH];
And use something like strcpy or strncpy to do the copying.
You also do not appear to be setting value anywhere

Declare a struct with zero values instead of random memory?

I have a struct like this:
typedef struct string {
unsigned long length;
unsigned *data;
} string;
Can I write something so that when I do this:
string s;
the length property is zero, instead of whatever happens to be in the memory? data works well, as it's preset to zero or a null pointer.
Example of what happens right now:
string s;
printf("length: %lu\n", s.length);
printf("pointer: %lu\n", (unsigned long) s.data);
Result:
length: 140737488347584
pointer: 0
I want to avoid having to call an initialisation function on each new string just to set length to zero.
More information
Now that I think about it, it may not be really necessary to do this in my particular case (though it would be nice) because most people would initially set the string through ctou (which imports UTF-8 from char pointer) and that function sets length to zero anyway.
You could use
string s = {0,NULL};
To combine the two previous answers (sort of) I'd define something like
#define STRING_INITIALIZER {0, NULL}
.
.
string s = STRING_INITIALIZER;
BTW, your struct declaration itself looks weird for a string. Either this is not a string as we usually understand it in C but merely a dynamic array of unsigned, or it is really a string and then this should be char*.
The accepted answer answered the question that you asked, but didn't address whether you ought.
Your string is a class and has class semantics. The initializer may be fine for kernel code where every last instruction counts, but in application code your static initializers are ugly and error prone.
It is possible to write classes in C, the stdio FILE type is a fabulous example, and here is the same idea applied to your string class:
typedef struct {
int length;
char *data;
} String;
String *sopen() {
String *s = malloc(sizeof(String));
if(s) {
s->length = 0;
s->data = NULL;
}
return s;
}
int sclose(String *s) {
free(s->data);
free(s);
return 0;
}
int main()
{
String *s = sopen();
return sclose(s);
}
Where I've followed the FILE* function name style for metaphoric reasons. Yep, there's more code. Yep, you have to explicitly deallocate the structure; but note that even though you were counting on auto class initialization in your code sample, if data was ever allocated, you couldn't count on leaving scope to automatically deallocate the storage for you.
This approach also has the merit of abstracting the type of data from the users of the class. As there seems to be some confusion about what type you really want to use, this flexibility may come in handy.
#define DEFINE_STRING(s) string s = {0, NULL}
{
DEFINE_STRING(s);
}
You can use a macro to "do this automatically"

Resources