missing entries in array of string values - c

I'm trying to create a const char array of strings used to identify some hardware channels. I then want to retrieve these entries by index to label outputs on a user console. Some of these channels are unassigned and labeled as such with a string "XX_UNASSIGNED_XX", so this value is repeated in the array.
When I try to sequentially display these values in my test code, I see that XX_UNASSIGNED_XX only appears once, and is subsequently skipped. I opened a memory trace in the embedded hardware, and sure enough, the memory only lists XX_UNASSIGNED_XX once, I'm assuming as a sort of optimization.
Is there a way to force the compiler to instead list out every entry in memory as is, duplicates and all? Or, is it possible that I don't need to do this, and the way I'm attempting to display the strings is incorrect or inefficient and could be improved?
I've played around with how I display the strings, and because it's ultimately a pointer array with each string a different length, I ultimately resulted in recording the length of each string, tracing the array with a pointer variable, then using snprintf to copy the string over to a temp string which I then display. Any attempt to print the values in the array directly kept resulting in anomalous behavior I couldn't seem to correct.
FYI The Display_printf command is simply a printf to the UART terminal with syntax as follows:
Display_printf(UART_handle,col_index, row_index, display_text))
#define ADC_COUNT (20)
const char* adcNamesArray[ADC_COUNT] = {
"KP_CUR_MON",
"A_CUR_MON",
"A_VOLT_MON",
"NEG_15_VOLT_MON",
"XX_UNASSIGNED_XX",
"FOCUS_CUR_MON",
"XX_UNASSIGNED_XX",
"XX_UNASSIGNED_XX",
"K_CUR_MON",
"XX_UNASSIGNED_XX",
"XX_UNASSIGNED_XX",
"XX_UNASSIGNED_XX",
"FOCUS_VOLT_MON",
"FARADAY_MON",
"MFC_MON",
"XX_UNASSIGNED_XX",
"POS_12_VOLT_MON",
"POS_24_VOLT_MON",
"POS_15_VOLT_MON",
"POS_5_VOLT_MON"
};
char str[20];
char* ptr = &adcNamesArray[0];
char* printPtr;
int nameLength;
for(int adc_index = 0; adc_index < ADC_COUNT; adc_index++) {
nameLength = 0;
while(*ptr == '\0') {
ptr += sizeof(char);
}
printPtr = ptr;
while(*ptr != '\0') {
ptr += sizeof(char);
nameLength++;
}
nameLength++;
char* str;
str = (char *)malloc((sizeof(char)*nameLength+1));
snprintf(str, nameLength, "%s", printPtr);
Display_printf(display,0,0,"ADC %d: %s", adc_index, str);
}
So, I expect all the XX_UNASSIGNED_XX entries to show up in order, but instead what I get is this:
ADC 0: KP_CUR_MON
ADC 1: A_CUR_MON
ADC 2: A_VOLT_MON
ADC 3: NEG_15_VOLT_MON
ADC 4: XX_UNASSIGNED_XX
ADC 5: FOCUS_CUR_MON
ADC 6: K_CUR_MON
ADC 7: FOCUS_VOLT_MON
ADC 8: FARADAY_MON
ADC 9: MFC_MON
ADC 10: POS_12_VOLT_MON
ADC 11: POS_24_VOLT_MON
ADC 12: POS_15_VOLT_MON
ADC 13: POS_5_VOLT_MON
ADC 14: ▒
ADC 15: #
ADC 16: ▒▒▒▒
ADC 17: #▒
ADC 18:
ADC 19:
A look at the memory dump gives this, which explains why XX_UNASSIGNED_XX doesn't show up multiple times.
0x0001C0D8 . . . . . . . 0 K P _ C U R _ M
0x0001C0E8 O N . . A _ C U R _ M O N . . .
0x0001C0F8 A _ V O L T _ M O N . . N E G _
0x0001C108 1 5 _ V O L T _ M O N . X X _ U
0x0001C118 N A S S I G N E D _ X X . . . .
0x0001C128 F O C U S _ C U R _ M O N . . .
0x0001C138 K _ C U R _ M O N . . . F O C U
0x0001C148 S _ V O L T _ M O N . . F A R A
0x0001C158 D A Y _ M O N . M F C _ M O N .
0x0001C168 P O S _ 1 2 _ V O L T _ M O N .
0x0001C178 P O S _ 2 4 _ V O L T _ M O N .
0x0001C188 P O S _ 1 5 _ V O L T _ M O N .
0x0001C198 P O S _ 5 _ V O L T _ M O N . .
0x0001C1A8 uartMSP432E4HWAttrs
0x0001C1A8 . . . # . . . . . . . . . . . .
0x0001C1B8 # . . . . . . . . . . . . . . .
Any help is appreciated.

You assume that the texts are contiguous in memory separated by one or more NUL characters. This assumption is wrong.
This declares an array of pointers to your texts:
const char* adcNamesArray[ADC_COUNT] = {
...
Just use that array and all of a sudden your code becomes much simpler and correct.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ADC_COUNT (20)
int main(void)
{
const char* adcNamesArray[ADC_COUNT] = {
"KP_CUR_MON",
"A_CUR_MON",
"A_VOLT_MON",
"NEG_15_VOLT_MON",
"XX_UNASSIGNED_XX",
"FOCUS_CUR_MON",
"XX_UNASSIGNED_XX",
"XX_UNASSIGNED_XX",
"K_CUR_MON",
"XX_UNASSIGNED_XX",
"XX_UNASSIGNED_XX",
"XX_UNASSIGNED_XX",
"FOCUS_VOLT_MON",
"FARADAY_MON",
"MFC_MON",
"XX_UNASSIGNED_XX",
"POS_12_VOLT_MON",
"POS_24_VOLT_MON",
"POS_15_VOLT_MON",
"POS_5_VOLT_MON"
};
for (int adc_index = 0; adc_index < ADC_COUNT; adc_index++)
{
char *str = malloc(strlen(adcNamesArray[adc_index]) + 1);
strcpy(str, adcNamesArray[adc_index]);
printf("ADC %d: %s\n", adc_index, str);
}
}
If you don't have strcpy or strlen on your platform for whatever reason, you can implement them yourself, they are one-liners.
Some explanations:
sizeof char is 1 by definition, so you can drop it
the (char*) cast is not necessary with malloc, it's not wrong to put one, but there is zero benefit in doing so.

Related

Is there a way to implement Morse code inside an array? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I'm making my microcontroller display letters of the alphabet in Morse code using LEDS (dot == short blink, dash == long blink).
I could make a switch statement and do it like this :
switch (input)
case "a | A"
....
case "b | B "
....
but then I'd have a 27+ long switch statement, so I guess that's not very good?
I was thinking of making an array with all the Morse code inside but how do I implement this concept, that the first entry of the array equals a or A, ... ?
If we assume that your platform uses a character-encoding system in which the 26 Latin alphabet letters have consecutive values (the most common system used, ASCII, does, but it's not guaranteed by the C Standard), then we can define an array of strings for the Morse code for each letter and index into that array using the value of a given letter from which the value of 'A' has been subtracted.
We can also do a similar thing for digits (these are guaranteed by the Standard to have contiguous codes).
Here's a sample code (we convert all letters to uppercase before indexing into the Morse array):
#include <stdio.h>
#include <ctype.h>
int main()
{
const char* Alpha[26] = {
".-", // A
"-...", // B
"-.-.", // C
"-..", // D
".", // E
".._.", // F
"--.", // G
"....", // H
"..", // I
".---", // J
"-.-", // K
".-..", // L
"--", // M
"-.", // N
"---", // O
".--.", // P
"--.-", // Q
".-.", // R
"...", // S
"-", // T
"..-", // U
"...-", // V
".--", // W
"-..-", // X
"-.--", // Y
"--.." // Z
};
const char* Digit[10] = {
"-----",// 0
".----",// 1
"..---",// 2
"...--",// 3
"....-",// 4
".....",// 5
"-....",// 6
"--...",// 7
"---..",// 8
"----.",// 9
};
char input[256];
do {
printf("Enter text ($ to quit): ");
scanf("%255s", input);
printf("Morse code...\n");
for (char *c = input; *c; ++c) {
if (isalpha(*c)) printf("%s", Alpha[toupper(*c) - 'A']);
else if (isdigit(*c)) printf("%s", Digit[*c - '0']);
else if (*c != '$') printf("<error>");
printf("\n");
}
} while (input[0] != '$');
return 0;
}
If we can not rely on contiguous codes for the letters (or choose not to, for a more robust implementation), we can determine the index by calling the strchr function (we must then #include <string.h>) to get our letter's position in a list of all letters:
//...
const char* Letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
//...
if (isalpha(*c)) printf("%s", Alpha[strchr(Letters,toupper(*c)) - Letters]);
Please feel free to ask for any further clarification and/or explanation.
An alternative to #Adrian's, just encode most of the ASCII character set - from space (32) to capital Z (91). You'll get numbers, letters, punctuation, and pro-signs, and some we don't care about, but who cares, because it simplifies things so much. You're on a 8-bit microcontroller, so you don't have to worry about character encoding and OS preferences and all that trash.
Further more, skip the strings. They'll just take up room in your limited RAM, unless you do the F("asd") trick with Arduino to put them in flash. Instead of strings, use ones and zeros: 0b0110000 read from left to right to get dot, dash, sentinel stop bit, followed by padding zeros. Looks nasty but really isn't.
Here's what I have...
/*
* Bit packing: read left to right from MSB, 0=dit, 1=dah,
* with extra dah terminating sentinel, then zero filled on right.
* Example,
* letter D -.. "dahdidit"
* convert 100
* terminate 1001
* pad 10010000
* result 0b10010000
* To use, test the top bit, send dit or dah, shift left, end when result is $80.
*/
/*
* the character codes are in ASCII order,
* from space $20 to underscore $5F or 32-95 decimal.
* lower-case alpha should be coverted to upper-case before lookup
*/
const charcodes[] PROGMEM = {
0, // $20 space
0b10101110, // ! exclamation point /KW
0b01001010, // " double quote /AF
0, // # hash mark, octothorpe
0b00010011, // $ dollar sign /SX
0, // % percent sign or /KA ?
0b01000100, // & ampersand /AS
0b01111010, // ' single quote /WG
0b10110100, // $28 ( left parenthesis /KN
0b10110110, // ) right parenthesis /KK EOW ? EOM
0b00010110, // * asterisk /SK
0b01010100, // + plus sign
0b11001110, // , comma
0b10000110, // - dash, hyphen /DU
0b01010110, // . period
0b10010100, // / slash, divide /DN
0b11111100, // $30 0
0b01111100, // 1
0b00111100, // 2
0b00011100, // 3
0b00001100, // 4
0b00000100, // 5
0b10000100, // 6
0b11000100, // 7
0b11100100, // $38 8
0b11110100, // 9
0b11100010, // : colon /OS
0b10101010, // ; semicolon /KR
0, // < less-than sign
0b10001100, // = equal sign /BT
0, // > greater-than sign
0b00110010, // ? question mark
0b01101010, // $40 # commercial 'at' sign /AC
0b01100000, // A
0b10001000, // B
0b10101000, // C
0b10010000, // D
0b01000000, // E
0b00101000, // F
0b11010000, // G
0b00001000, // $48 H
0b00100000, // I
0b01111000, // J
0b10110000, // K
0b01001000, // L
0b11100000, // M
0b10100000, // N
0b11110000, // O
0b01101000, // $50 P
0b11011000, // Q
0b01010000, // R
0b00010000, // S
0b11000000, // T
0b00110000, // U
0b00011000, // V
0b01110000, // W
0b10011000, // $58 X
0b10111000, // Y
0b11001000, // Z
0, // [ left bracket
0, // \ back-slash
0, // ] right bracket
0, // ^
0b00110110, // $5F _ underscore /IQ
};
/*
* look up the code for an ASCII character
* return 0 for bad characters and characters out of range.
*/
byte getcode(char c)
{
// convert upper-case to lower-case
if ( c >= 'a' && c <= 'z' )
c -= 'a' - 'A';
// check for characters beyond our table
if ( c < ' ' || c > '_' )
return 0;
// else read the byte from flash
return pgm_read_byte(charcodes + c - ' ');
}
I'm sure the smart folks will find problems, and I'll learn from them. Have fun!
EDIT: and they did! #Clifford pointed out that I didn't show how to use the encoded byte. So here it is... you'll have to define your values for length of dit, dah, element gap (between dits and dahs), character gap (between characters) and word gap (between words):
#define TOPBIT 0x80
void key(byte c)
{
// while we're not done, start the tone, delay a bit, stop the tone
while ( c != TOPBIT && c != 0 ) {
tone(BUZZ, FREQ);
digitalWrite(LED, 1);
delay( (c & TOPBIT) ? dahLen : ditLen );
noTone(BUZZ);
digitalWrite(LED, 0);
delay(elemGap);
// shift left one place; test the next bit the next time around
c <<= 1;
}
// now generate a character space
delay(charGap - elemGap);
}
HTH! (Thanks #Clifford)

Comparing paths with special characters on Mac UTF-8

We have a kext that checks if a path is a subdir of another path and does some magic if it is.
This all works fine as long we don't have special characters in our path (characters like ë)
We feed some working paths into the system by a helper application that can communicate with the kext.
I've isolated the problem to this code:
#include <stdio.h>
#include <string.h>
int main ()
{
char* path = "/Users/user/test/tëst/test"; //Sent by the system
char* wp = "/Users/user/test/tëst"; //Some path we claim to be ours
size_t wp_len = strlen(wp);
if (strncmp (wp,path,wp_len) == 0) //Check is path is a subpath
{
printf ("matched %s\n", path);
}else {
printf ("could not match\n");
}
return 0;
}
I've created a Gist, so the encoding does not go lost with the browser: https://gist.github.com/fvandepitte/ec28f4321a48061808d0095853af7bd7
Someone knows how i can check if path is a subpath of wp without losing too much performance (this code runs in the kernel)?
I've copy/pasted the source straight from the browser into a file (test.c). It prints could not match for me.
If I dump the file using od this is what I see:
bash-3.2$ od -c test.c
0000000 # i n c l u d e < s t d i o .
0000020 h > \n # i n c l u d e < s t r
0000040 i n g . h > \n \n i n t m a i n
0000060 ( ) \n { \n c h a r * p a
0000100 t h = " / U s e r s / u s e
0000120 r / t e s t / t ë ** s t / t e s
0000140 t " ; / / S e n t b y t h
0000160 e s y s t e m \n c h a r *
0000200 w p = " / U s e r s /
0000220 u s e r / t e s t / t e ̈ ** s t
0000240 " ; / / S o m e p a t h w
Notice that the tëst of path comes out as t ë ** s t,
but the tëst of wp comes out as t e ̈ ** s t, which is different: so strncmp will fail when comparing ë and e.
If I copy the tëst from path paste that into wp's assignment then I get matched /Users/user/test/tëst/test, so strncmp seems to work fine.
I don't know these two strings differ like this, I can only assume that the two strings are using different encodings somehow. The strncmp function compares strings per byte, so ë and e ̈ are considered different. If you want to use strncmp, then unfortunately there's no easy solution to this other than insuring that both strings use the same encoding.
FWIW - I'm running on macOS 10.12.1, with clang version Apple LLVM version 8.0.0 (clang-800.0.42.1)
EDIT: I've downloaded pathtest.cpp from your github link just to double-check things. I've run od -c pathtest.cpp and I see the same problem.

WinDBG conditional breakpoint based on string arguments

I want to set a conditional breakpoint when the value of the 4th argument is equal to "abc".
void FunctionA(char* a, char* b, char* c, char* d)
{
`enter code here`//some code here
}
I use the following command but it doesn't work. Could you help?
bp app!FunctionA "as /mu ${/v:MyAlias} poi(d);.block{.if ($spat(\"${MyAlias}\", \"abc\") == 0) { } .else { gc } }"
Note: app.exe is my application name.
you cannot use /mu on char * /mu is for null terminated unicode string not ascii string for ascii string use /ma
I assume you have descriptive argument names and not an argument like d
which would obviously clash with 0xd aka 0n13
is d a number , string or symbol ??
what would poi(d) resolve to in your case is it poi(0x13) which obviously is a bad de-referance
or a local symbol illogically named d ??
also alias is not interpreted when you break
when using alias you should always stuff them in a script file and execute
the script file on each break
here is an example of a script file
as /ma ${/v:MyAlias} poi(k)
.block {
r $t0 = $spat("${MyAlias}" , "tiger")
.printf "%x\t${MyAlias}\n" , #$t0
.if(#$t0 != 1) {gc}
}
here is code on which this is operated comipled in debug mode with optimizations turned off
in release mode compiler will be smart enough to inline the printf() call
#include <stdio.h>
#include <stdlib.h> //msvc _countof
void func(char* h,char* i,char* j,char* k ) {
printf( "%s %s %s %s\n" ,h,i,j,k );
return;
}
int main(void) {
char* foo[] = {"goat","dog","sheep","cat","lion","tiger",0,"vampire"};
for(int x=0;x<_countof(foo);x++) {
func("this" , "is" , "a" , foo[x]);
}
return 0;
}
usage
windbg app.exe
set the break and run
keep in mind this or any script that uses alias will fail on
evaluating the null entry before char * vampire
if you want to break on "vampire" you may need to improvise without using alias at all
0:000> bl
0:000> bp strbp!func "$$>a< strbpcond.txt"
0:000> bl
0 e 00171260 0001 (0001) 0:**** strbp!func "$$>a< strbpcond.txt"
0:000> g
ModLoad: 72670000 72673000 C:\Windows\system32\api-ms-win-core-synch-l1-2-0.DLL
0 goat
0 dog
0 sheep
0 cat
0 lion
1 tiger
eax=00000005 ebx=7ffd7000 ecx=00000005 edx=001ac1e0 esi=001b6678 edi=001b667c
eip=00171260 esp=002bfa54 ebp=002bfa90 iopl=0 nv up ei ng nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000293
strbp!func:
00171260 55 push ebp
0:000> dv
h = 0x001ac1f8 "this"
i = 0x001ac1f4 "is"
j = 0x001ac1f0 "a"
k = 0x001ac1e0 "tiger"

Haskell Array Index out of range

My code is pasted here.
Below is my ghci debug session. I still don't understand why it has a range of (0, -193459561) when the 'len' binding is 90570.
*Main> :break 125
Breakpoint 4 activated at SVMCF.hs:125:13-86
*Main> :trace main
Stopped at SVMCF.hs:125:13-86
_result :: UA.Array Int [User] = _
len :: Int = 90570
rts :: [RTuple] = (1,1,5.0) : (1,2,3.0) : (1,3,4.0) : (1,4,3.0) :
(1,5,3.0) : ....
[SVMCF.hs:125:13-86] *Main> :lis
124 points :: A.Array Int [Int]
125 points = assert (len > 0) $ A.listArray (1::Int, len) $ map (\(u,i,r) -> [u,i]) rts
126 values :: UA.UArray Int Double
[SVMCF.hs:125:13-86] *Main> :ste
Stopped at SVMCF.hs:125:13-28
_result :: UA.Array Int [User] -> UA.Array Int [User] = _
len :: Int = 90570
[SVMCF.hs:125:13-28] *Main> :ste
Stopped at SVMCF.hs:125:21-27
_result :: Bool = _
len :: Int = 90570
[SVMCF.hs:125:21-27] *Main> :ste
Stopped at SVMCF.hs:125:32-86
_result :: UA.Array Int [User] = _
len :: Int = 90570
rts :: [RTuple] = (1,1,5.0) : (1,2,3.0) : (1,3,4.0) : (1,4,3.0) :
(1,5,3.0) : ....
[SVMCF.hs:125:32-86] *Main> :ste
Stopped at SVMCF.hs:125:32-56
_result :: [[User]] -> UA.Array Int [User] = _
len :: Int = 90570
[SVMCF.hs:125:32-56] *Main> :lis
124 points :: A.Array Int [Int]
125 points = assert (len > 0) $ A.listArray (1::Int, len) $ map (\(u,i,r) -> [u,i]) rts
126 values :: UA.UArray Int Double
[SVMCF.hs:125:32-56] *Main> len
90570
[SVMCF.hs:125:32-56] *Main> :ste
Stopped at SVMCF.hs:125:60-86
_result :: [[User]] = _
rts :: [RTuple] = (1,1,5.0) : (1,2,3.0) : (1,3,4.0) : (1,4,3.0) :
(1,5,3.0) : ....
[SVMCF.hs:125:60-86] *Main> :ste
*** Exception: Ix{Int}.index: Index (1) out of range ((1,-193459561))
I suspect the index out of range exception is not being caused in the expression that you think it is!
Data.Array.listArray (1,-10) [2,3,4,5]
does not throw any exception, it just gives you an empty array. Also note the column numbers in the last debug message:
Stopped at SVMCF.hs:125:60-86
60 to 86 is map (\(u,i,r) -> [u,i]) rts which doesn't obviously have any indexing going on in it: There's certainly none in map, nor in its first argument, and rts looks clean too as it comes straight from ua.base via Parsec.
Because Haskell is allowed to be fairly free with its evaluation order, it's possible that the exception is being thrown by a reduction in a completely different expression. Are you sure all the other things you're passing into SVM are set up correctly? In particular, given that you're using Int-indexed arrays, are you sure there's no integer overflow occurring in any array? Are any of your datasets, for example, 4101507735 or 8396475031 records long, because these overflow to -193459561 as Int).
Does the :history command in the GHCi debugger give you any more information?

Overwriting lines in file in C

I'm doing a project on filesystems on a university operating systems course, my C program should simulate a simple filesystem in a human-readable file, so the file should be based on lines, a line will be a "sector". I've learned, that lines must be of the same length to be overwritten, so I'll pad them with ascii zeroes till the end of the line and leave a certain amount of lines of ascii zeroes that can be filled later.
Now I'm making a test program to see if it works like I want it to, but it doesnt. The critical part of my code:
file = fopen("irasproba_tesztfajl.txt", "r+"); //it is previously loaded with 10 copies of the line I'll print later in reverse order
/* this finds the 3rd line */
int count = 0; //how much have we gone yet?
char c;
while(count != 2) {
if((c = fgetc(file)) == '\n') count++;
}
fflush(file);
fprintf(file, "- . , M N B V C X Y Í Ű Á É L K J H G F D S A Ú Ő P O I U Z T R E W Q Ó Ü Ö 9 8 7 6 5 4 3 2 1 0\n");
fflush(file);
fclose(file);
Now it does nothing, the file stays the same. What could be the problem?
Thank you.
From here,
When a file is opened with a "+"
option, you may both read and write on
it. However, you may not perform an
output operation immediately after an
input operation; you must perform an
intervening "rewind" or "fseek".
Similarly, you may not perform an
input operation immediately after an
output operation; you must perform an
intervening "rewind" or "fseek".
So you've achieved that with fflush, but in order to write to the desired location you need to fseek back. This is how I implemented it - could be better I guess:
/* this finds the 3rd line */
int count = 0; //how much have we gone yet?
char c;
int position_in_file;
while(count != 2) {
if((c = fgetc(file)) == '\n') count++;
}
// Store the position
position_in_file = ftell(file);
// Reposition it
fseek(file,position_in_file,SEEK_SET); // Or fseek(file,ftell(file),SEEK_SET);
fprintf(file, "- . , M N B V C X Y Í Ű Á É L K J H G F D S A Ú Ő P O I U Z T R E W Q Ó Ü Ö 9 8 7 6 5 4 3 2 1 0\n");
fclose(file);
Also, as has been commented, you should check if your file has been opened successfully, i.e. before reading/writing to file, check:
file = fopen("irasproba_tesztfajl.txt", "r+");
if(file == NULL)
{
printf("Unable to open file!");
exit(1);
}

Resources