Iterate through int array of unknown length - c

I am trying to iterate through an array that will contain up to a maximum of 4 elements - no other knowledge of the array-length exists.
Pseudo Code
void insert_vals(uint8_t num, uint8_t *match_num, uint8_t *value)
{
uint8_t i;
while(data_exists) // how do I determine if data exists in 'value'?
{
switch(num)
{
case 0:
{
switch(match_num[i])
{
case 0:
hw0reg0 = value[i];
case 1:
hw0reg1 = value[i];
case 2:
hw0reg2 = value[i];
case 3:
hw0reg3 = value[i];
}
}
case 1:
{
switch(match_num[i])
{
case 0:
hw1reg0 = value[i];
case 1:
hw1reg1 = value[i];
case 2:
hw1reg2 = value[i];
case 3:
hw1reg3 = value[i];
}
}
// etc. 2 other cases
}
i++;
}
}
Calling Example (Pseudo Code)
/*
* num: hardware device select from 1 - 4
* match_num: 4 possible matches for each hardware device
* value: 32-bit values to be assigned to 4 possible matches
* NOTE: This function assumes hardware devices are selected
* in a consecutive order; I will change this later.
*/
// example calling code - we could have configured 4 hardware devices
insert_vals(0, [0, 1], [0x00000001, 0x000000FF]); // arg2 and arg3 equal in length
How can I accomplish this?
In a character array, C will automatically add '\0' to the end of the array, but this does not seem to be the case for an integer array. If I was somehow able to determine the length of match_num and value (see if statement) at runtime originally, then that would allow me to create a for loop.
Edit
Since I know that there will be a maximum of 4 elements, couldn't I do something similar to the following?
void insert_vals(uint8_t num, uint8_t *match_num, uint32_t *value)
{
int i;
for(i = 0; i < 4; i++)
{
if(value[i] == -1)
break;
else
{
// Assign data
}
}
}

You can't get the length of an array pointed to given only the pointer. Either you have to pass the length, or it must be constant (always 4) with some sentinel value in the unused elements -- a value that is somehow invalid for your computations (like NUL is for strings).

Is there a value you can guarantee it's not in the "usable" data? (e.g. 0 is no valid character for character strings, therefore Mr. Kernighan and Mr. Ritchie decided to pick it as a "end of array" marker. You could do the same with any value.
Say you know your integer values are between 0 to 512, so you could initialize the whole array e.g. to 1024, then fill it and iterate through it until a number >512 occurs (which has to be your end of array marker).
Another possibility is to pass the number of elements in the array along with the array.

Related

How to printf a vector in C

I have three diferent vectors with the name of diferents towns inside:
V_NombrePueblos listTown1={"Abrera","Granollers","Cardedeu","Manresa","Martorell"};
V_NombrePueblos listTown2={"Astorga","Benavente","Bembibre","Camarzana","Ferrol"};
V_NombrePueblos listTown3={"Arteijo","Betanzos","Cariño","Cedeira","Cerdido"};
The user tell me the number of vector and the position for print the town. I think in use a function with a switch inside for do this:
typedef char nameList[8];
void returnTown(int listTown, int position){
nameList numList;
if (listTown==0){
strcpy(numList, "listTown1");
}
if (listTown==1){
strcpy(numList, "listTown2");
}
if (listTown==2){
strcpy(numList, "listTown3");
}
switch (position){
case 1:
printf("%s", numList[0]);
break;
case 2:
printf("%s", numList[1]);
break;
case 3:
printf("%s", numList[2]);
break;
case 4:
printf("%s", numList[3]);
break;
case 5:
printf("%s", numList[4]);
break;
But when I try to print example:
returnTown(0,1)
The console doesn't show nothing, with the previus code the console should show "Abrera"
The problem is in the printf insede the switch,
If I put:
printf("%s",listTown1[0] )
The code show "Abrera" fine, but I need pass the name of the vector like a varName, because sometimes will be listTown1, other times listTown2 or listTown3...
Any idea?
Thanks
Copying names of variables doesn't mean refering variables.
To refer variables, you should use pointers.
You will want something like this:
void returnTown(int listTown, int position){
V_NombrePueblos* numList;
switch (listTown){
case 0: numList = &listTown1; break;
case 1: numList = &listTown2; break;
case 2: numList = &listTown3; break;
default: return;
}
if (1 <= position && position <= 5){
printf("%s", (*numList)[position - 1]);
(rest part of this function isn't shown because I respect the original code snippet)
What you are trying to do won't work in C - you can't build variable names dynamically like that.
Any time you find yourself defining a bunch of variables with the same type and with ordinal names (var1, var2, etc.), that's a real strong hint you want to use an array. In this case, you could do something like
/**
* I am *assuming* that vNombrePueblos is a typedef name for char *[5],
* based on the declarations in your code.
*
* The size of the listTowns array is taken from the number of initializers;
* in this case, 3.
*/
vNombrePueblos listTowns[] = {
{"Abrera","Granollers","Cardedeu","Manresa","Martorell"},
{"Astorga","Benavente","Bembibre","Camarzana","Ferrol"},
{"Arteijo","Betanzos","Cariño","Cedeira","Cerdido"}
};
This way instead of trying to figure out which listTownN variable you want, you just index into this array. To print out the correct town, all you need is the two indices:
/**
* You need to pass the list of towns as an argument to your function;
* since arrays lose their "array-ness" under most circumstances, you also
* have to pass the array size to make sure you don't try to access something
* past the end of it.
*/
void returnTown( vNombrePueblos listTowns[], int numTowns, int town, int position )
{
if ( town < numTowns )
printf( "%s\n", listTowns[town][position] );
else
fprintf( stderr, "No such entry\n" );
}
You'll need to keep track of the number of entries in listTowns yourself - arrays in C don't carry any metadata about their size, and under most circumstances (such as when you pass it as an argument to a function) an expression of type "array of T" will "decay" into an expression of type "pointer to T", so the sizeof arr / sizeof arr[0] trick won't work to get the number of elements.

c - correct struct element pointer arithmetic

I'm newbie C programmer working on maintaining some legacy embedded C code that looks problematic. In the following snippets I have simplified:
UINT16 adcFunc(UINT8 adc, UINT8 channel)
{
ADC_t* adc_ptr = (ADC_t*)(adc << 4);
ADC_CH_t* adc_ch_ptr;
adc_ch_ptr = (ADC_CH_t*)((UINT8*)&(adc_ptr->CH0) + sizeof(ADC_CH_t) * channel);
...
}
Where the structure definition is given as:
typedef struct ADC_struct
{
...
register8_t reserved_0x1E;
register8_t reserved_0x1F;
ADC_CH_t CH0; /* ADC Channel 0 */
ADC_CH_t CH1; /* ADC Channel 1 */
ADC_CH_t CH2; /* ADC Channel 2 */
ADC_CH_t CH3; /* ADC Channel 3 */
} ADC_t;
With the pointer size being 2 bytes and UINT8 represented as a typedef unsigned char. When linting the code, my linter reports back a warning
cast from UINT8* to ADC_CH_t* increases required alignment from 1 to 2 on the line
adc_ch_ptr = (ADC_CH_t*)((UINT8*)&(adc_ptr->CH0) + sizeof(ADC_CH_t) * channel);
The code is trying to calculate the correct offset into the struct for the channel pointer adc_ch_ptr (where channel is between 0 and 3) It looks like a strict aliasing violation to me and I removed the cast from (UINT8*) senselessly and it crashed the application.
Can anyone shed some light on how to correctly calculate the pointer to the correct channel without aliasing and padding/alignment issues?
Thanks
Avoid this pointer magic, and trust the compiler to understand the switch:
UINT16 adcFunc(UINT8 adc, UINT8 channel)
{
/* this should be hidden inside a macro or an inline function*/
ADC_t *adc_ptr = FIND_BASE_ADDRESS(adc);
ADC_CH_t *adc_ch_ptr;
switch (channel) {
case 0: adc_ch_ptr = &adc_ptr->CH0; break;
case 1: adc_ch_ptr = &adc_ptr->CH1; break;
case 2: adc_ch_ptr = &adc_ptr->CH2; break;
case 3: adc_ch_ptr = &adc_ptr->CH3; break;
/* should not happen ... */
default: return 0xffff;
}
/* do something with adc_ch_ptr ... */
...
return something_usefull_here;
}
Two simple solutions are:
Ignore your “linter”. Leave the code as it is.
Change adc_ch_ptr = (ADC_CH_t*)((UINT8*)&(adc_ptr->CH0) + sizeof(ADC_CH_t) * channel); to adc_ch_ptr = &adc_ptr->CH0 + channel;.
Either of these relies on the address arithmetic working beyond what the C standard requires and the structure not having any weird (and unnecessary) padding. Slightly more complicated solutions using strictly conforming C code are below.
The changed code above simply treats the CH* members as if they were an array of ADC_CH_t; adding an integer channel to a pointer to the first element (with index 0) of an array produces a pointer to another element in the array (with index channel). The original code does the same arithmetic except in units of bytes instead of elements of type ADC_CH_t. It appears unnecessary to use bytes, as the arithmetic with elements should produce the same results. So it is unclear why the original author chose to use bytes, given that the resulting code is more cumbersome.
Two solutions that use strictly conforming C code are:
Use an array (defined here as a compound literal) to look up the desired address:
adc_ch_ptr = (ADC_CH_t *[]) {
&adc_ptr->CH0, &adc_ptr->CH1, &adc_ptr->CH2, &adc_ptr->CH3,
} [channel];
Use a switch:
switch (channel)
{
case 0: adc_ch_ptr = &adc_ptr->CH0; break;
case 1: adc_ch_ptr = &adc_ptr->CH1; break;
case 2: adc_ch_ptr = &adc_ptr->CH2; break;
case 3: adc_ch_ptr = &adc_ptr->CH3; break;
}

Char** array first element being modified magically

I am sorry for the vague title, but I am having a very hard time figuring out how to describe this issue. I am trying to add data to an array and somehow it is all getting written to index 0 despite my explicitly indicating otherwise. I have created a minimal sample.
Expected Behavior
With command line arguments as -u rwx -g rw -o r:
bins[0] == "111"
bins[1] == "110"
bins[2] == "100"
Actual Behavior
Indices 0, 1 and 2 all end up as "100". If you put a printf() to check their value inside the various case statements, you will find that, for instance, when case 'g': runs, bins[1] == "110" AND bins[0] == "110". When case 'o': runs, all three indices will will hold the value "100".
Minimal functional sample
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void processPerms(char *targets, char **perms, char **bins, const size_t arrSize) {
for(int i = 0; i < arrSize; i++) {
//This string will be modified
//so that the right bits will
//be set.
char binDig[] = "000";
//We decide which, if any, bit
//to set based upon the current
//letter being considered.
for(int k = 0; k < strlen(perms[i]); k++) {
switch(perms[i][k]) {
case 'r':
binDig[0] = '1';
break;
case 'w':
binDig[1] = '1';
break;
case 'x':
binDig[2] = '1';
break;
}
}
//Here, we check the target
//whose index corresponds to
//the index of the permissions
//string we just accessed.
//They will always be in
//an order where the related
//target and perm str are in
//the same array position.
switch(targets[i]) {
case 'u':
bins[0] = binDig;
//bins[0] == "111"
break;
case 'g':
bins[1] = binDig;
//bins[0] == "110"
break;
case 'o':
bins[2] = binDig;
//bins[0] == "100" && bins[1] == "100"
break;
}
}
}
int main(int argc, char *argv[]) {
const size_t arrSize = (argc-1)/2;
char *targets = (char*)calloc(arrSize, sizeof(char));
char **perms = (char**)calloc(arrSize, sizeof(char*));
//Copying just the letters
//of the args into these
//arrays.
for(int i = 0; i < arrSize; i++) {
targets[i] = argv[i+(i+1)][1];
}
for(int i = 0; i < arrSize; i++) {
perms[i] = argv[i*2+2];
}
//This array should hold three
//strings which shall be binary
//representations of the
//permissions
char **bins = (char**)calloc(3, sizeof(char*));
processPerms(targets, perms, bins, arrSize);
return 0;
}
bins[2] = binDig;
This will make you point to a variable which has automatic storage duration. This is a gateway to undefined behavior when you are returning it from the function. The life time of the variable is over as in this case and accessing it is UB.(Dereferencing a pointer to variable beyond its lifetime is Undefine d behavior).
A easy solution would be to use (This is part of POSIX standard but it is common enough) (In case you don't have this, you can allocate memory and copy to it the content of the array binDig).
bins[2] = strdup(binDig);
(Make the same changes for bins[0] and bins[1]).
Making this change as mentioned gives the expected behavior of being bins[0] equal to "111" and so on. The only thing is that, you need to free the dynamically allocated memory (including as that of returned by strdup
when you are done working with it). Similarly, don't cast the return value of malloc,calloc etc(because void* to char* is an implicit conversion). And check the return value of malloc/calloc.
The lifetime of you binDig array is limited by one iteration of the outer for cycle. This binDig array gets destroyed at the end of each iteration and created anew at the beginning of the next iteration.
This means that everything you do during each iteration of the outer cycle is lost when that iteration ends. The value of bins[] that you assigned during that iteration begins to point to some indeterminate location in memory where nothing exists anymore. Any attempts to access data through the corresponding bins[] entries lead to undefined behavior.
In real life each iteration of the cycle will typically recreate binDig at exactly the same location in memory, which creates an illusion of all of your bins[] pointers remaining valid but pointing to the same value. But this is a mere illusion. The behavior is already undefined at that point.
When the outer cycle ends the binDig array disappears forever and all your bins[] pointers become hopelessly invalid for good. But that's just the last straw. Your program died well before that moment.

How to create array of random strings in C?

I tried creating an array of ten random strings that would print directions randomly. Such as first time "up down right ... rot_x" and second time "forward rot_y up ... down" etc. I tried using a char* pc and allocating memory for it with memset but that didn't work so I tried the following code but I'm getting weird output. How can I fix this?
int main()
{
int r_num;
char r_arr[10][10];
for (int i = 0; i < 10; i++)
{
r_num = rand() % 10;
switch(r_num)
{
case 0: strcpy(r_arr[0], "up");
break;
case 1: strcpy(r_arr[1], "down");
break;
case 2: strcpy(r_arr[2], "left");
break;
case 3: strcpy(r_arr[3], "right");
break;
case 4: strcpy(r_arr[4], "rot_x");
break;
case 5: strcpy(r_arr[5], "rot_y");
break;
case 6: strcpy(r_arr[6], "rot_z");
break;
case 7: strcpy(r_arr[7], "forward");
break;
case 8: strcpy(r_arr[8], "back");
break;
case 9: strcpy(r_arr[9], "reset");
break;
default:
fprintf(stderr, "Cannot process input/n");
}
}
for (int i = 0; i < 10; i++)
{
printf("%s ", r_arr[i]);
}
return 0;
}
here's my output:
up ?V? left right rot_x ?V? forward back reset
A few problems with your code are:
You aren't seeding rand(), so every run of your program will generate identical output. You need to use srand() first with a seed. Traditionally one uses time().
Secondly despite the randomness you are unrandomly (is that a word?) filling r_arr. "up" will always be first, "down" will always be second etc.... Instead you should do something like
for (int = 0; i< 10; i++) {
r_num = rand() % 10;
strcpy(r_arr[i], getDirection(r_num));
}
where getDirection() will return a string based on an integer input (e.g.: via a case statement that associates 0 with "up").
Your r_arr needs to be initialized. There is no guarantee in your current code that each entry in the array will be populated with chars before being accessed. If you implement suggestion 2 then you wont have a problem. Today however your code is accessing potentially uninitialized memory.
As noted by others above, your issue is that you're not indexing your array with the iteration number of your loop. You had:
case 0: strcpy(r_arr[0], "up");
Whereas you should have had:
case 0: strcpy(r_arr[i], "up");
The additional thing that I wanted to point out is that rand() uses a linear equation (at least on many systems) so it will be impossible for you to ever get two even numbers in a row or two odd numbers in a row, which is not very random. Hence I suggest something like:
r_num = (rand() >> 8) % 10;
As the commenters pointed out, you are randomizing not what value you put in each position but which positions get filled with their preset value. Also, your use of a switch statement here is just odd. Try something like:
char value_arr[10][10]={"up", "down", "left", "right", "rot_x", "rot_y", "rot_z", "forward", "back", "reset"}
for (int i = 0; i < 10; i++)
{
r_num = rand() % 10;
strcpy(r_arr[i], value_arr[r_num]);
}
Print the strings inside the switch instead of the for-loop at the end.
Maybe you'll also need something like:
srand (time(NULL));
here is a code that fits exactly to your need :
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
int main()
{
// we use this instruction to get a random result each time we run the program
srand(time(NULL));
int r_num;
char r_arr[10][10];
// the dictionary array will be used to take from it the possible strings
char dictionary[10][10]={"up","down","left","right","rot_x","rot_x","rot_x","forward","back","reset"};
int i=0;
for(i=0; i<10; i++)
{
// r_num will be assigned randomly an index from dictionary tab
// the general equation is (rand()%(max-min+1))+min to get a random value
// between max and min inclusive
r_num=(rand()%(9-0+1))+0;
// we will put the random string chosen in the array r_num each time
strcpy(r_arr[i],dictionary[r_num]);
}
// this loop will print the result
for(i=0; i<10; i++)
{
printf("r_arr[%d]=%s \n",i,r_arr[i]);
}
return 0;
}
by looking at your output i noticed some strange values like ?v?,
the problem is that not all numbers between 0 and 9 will be generated by
the rand() function which mean that the corresponding array element(to those numbers) will not be initialized and therefor it contain garbage values from what ever was stored in that memory address.
i hope that explain why you are getting those strange values.

C: defining multidimensional arrays in a switch

I'm translating code from Maple to C in order to optimize performance. In order to save time, I've hard coded a 2-dimensional array for the 3 cases that I need to run asap. Later I'll add functions that generate this array so that I can run any case.
Here's how I tried to define the array schur: (here N and dim are pre-determined ints, and numPar is an int as well).
// load Schur functions
switch (N) {
case 3:
numPar = 3;
int schur[numPar][dim] = {
{1,0,0,0},
{0,1,1,0},
{0,0,0,1},
};
break;
case 4:
numPar = 5;
int schur[numPar][dim] = {
{1,0,0,0,0,0,0,0},
{0,1,1,0,1,0,0,0},
{0,0,1,0,0,1,0,0},
{0,0,0,1,0,1,1,0},
{0,0,0,0,0,0,0,1},
};
break;
case 5:
numPar = 7;
int schur[numPar][dim] = {
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,1,0,1,0,0,0,1,0,0,0,0,0,0,0},
{0,0,1,0,1,1,0,0,0,1,1,0,0,0,0,0},
{0,0,0,1,0,1,1,0,0,1,1,0,1,0,0,0},
{0,0,0,0,0,1,1,0,0,0,1,1,0,1,0,0},
{0,0,0,0,0,0,0,1,0,0,0,1,0,1,1,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
};
break;
default:
}
Clearly this will not work. However, I'm at a loss as to how to rewrite it so that it does work. One idea is to flatten the array, but that will obfuscate my code rather badly later on. Suggestions are greatly appreciated.
You can allocate the multidimensional array to be as large as the largest case. Based on the switch case you can only fill it to the size you need, and then only access it to the size you filled.
So for example for the 3 by 4 array:
int staticArray[3][4] = {
{1,0,0,0},
{0,1,1,0},
{0,0,0,1},
};
for (int i = 0; i<3; ++i) {
for (int j = 0; j<4; ++j) {
schur[i][j] = staticArray[i][j];
}
}
Since you're concerned about space, and since your larger arrays appear to be mostly zeros with relatively few ones, you might want to consider a "sparse array" solution. Access speed would be much slower, but the amount of memory used might be much less.
Websearching on that phrase will find implementations; which one would be best depends on how you intend to use these arrays.
switch (N) {
case 3:
numPar = 3;
int tmp1[3][dim] = {
{1,0,0,0},
{0,1,1,0},
{0,0,0,1},
};//then copy this rray to thry you want
break;
case 4:
numPar = 5;
int tmp2[5][dim] = {
{1,0,0,0,0,0,0,0},
{0,1,1,0,1,0,0,0},
{0,0,1,0,0,1,0,0},
{0,0,0,1,0,1,1,0},
{0,0,0,0,0,0,0,1},
};//then copy this rray to thry you want
break;
case 5:
numPar = 7;
int tmp3[7][dim] = {
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,1,0,1,0,0,0,1,0,0,0,0,0,0,0},
{0,0,1,0,1,1,0,0,0,1,1,0,0,0,0,0},
{0,0,0,1,0,1,1,0,0,1,1,0,1,0,0,0},
{0,0,0,0,0,1,1,0,0,0,1,1,0,1,0,0},
{0,0,0,0,0,0,0,1,0,0,0,1,0,1,1,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
};//then copy this rray to thry you want
break;
default:
}
First, note the hopefully obvious problem that you can't use variables when declaring an array in C, only constants. For example, your first declaration could work like this:
int schur[][] = {
{1,0,0,0},
{0,1,1,0},
{0,0,0,1}
};
and the compiler will happily figure out just how much space to allocate ... if, of course, you also weren't trying to declare the same variable multiple times in your switch statement. :-)
The second thing to keep in mind is that the construct:
int myArray[][] = { {1, 0, ... }, { 0, 1, ... }, ... };
declares an array of pointers to arrays of integers. In that example, schur is an array of 3 pointers, each of which points to an array of 4 integers.
This being C, there is of course a number of different ways to accomplish what you're trying to do. (Steve's Law of Computing: "If there exists one way to do something, there exists an infinite number of ways to do the same thing.")
What comes to mind first for the three cases you show above is to declare the 3 arrays you need, then just return the appropriate one from the switch statement:
int schur3[][] = {
{1,0,0,0},
{0,1,1,0},
{0,0,0,1}
};
int schur4[][] = {
{1,0,0,0,0,0,0,0},
{0,1,1,0,1,0,0,0},
{0,0,1,0,0,1,0,0},
{0,0,0,1,0,1,1,0},
{0,0,0,0,0,0,0,1}
};
int schur5[][] = {
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,1,0,1,0,0,0,1,0,0,0,0,0,0,0},
{0,0,1,0,1,1,0,0,0,1,1,0,0,0,0,0},
{0,0,0,1,0,1,1,0,0,1,1,0,1,0,0,0},
{0,0,0,0,0,1,1,0,0,0,1,1,0,1,0,0},
{0,0,0,0,0,0,0,1,0,0,0,1,0,1,1,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}
};
/* Note that what you get is a pointer to an array of pointers! */
int * * getSchurArray(int N)
{
switch (N)
{
case 3:
return (schur3);
case 4:
return (schur4);
case 5:
return (schur5);
}
}
(Caveat: No, I didn't run that through a compiler yet, so I won't guarantee there are no typos!)
Now, if you want to make this dynamic, and you really want to stick with C, you're going to have to use malloc(), which is how you do dynamic arrays in C. In your case, you need to do something along the lines of:
int * * createSchurArray(int numPar, int dim)
{
/* malloc() requires number of bytes, which is number of entries */
/* times the size of each entry. */
int * * answer = malloc(numPar * sizeof(int *));
for (int rowIndex = 0; rowIndex < numPar; rowIndex++)
{
answer[rowIndex] = malloc(dim * sizeof(int));
for (int colIndex = 0; colIndex < dim; colIndex++)
{
answer[rowIndex][colIndex] = schurValue(numPar, dim, rowIndex, colIndex);
}
}
}
where implementation of:
int schurValue(int numPar, int dim, int rowIndex, int colIndex)
is left as an exercise for someone who understands what you're trying to do with Schur functions. :-)
(Oh, wait - did I break an "only one smiley per answer" rule?)

Resources