4

How I can read a text file with comma separated hex values e.g. 0x58,0xA9,0x00 and put its values as elements of an array e.g. LR0 I need to replace this hard-coded with reading from the file:

const unsigned char LR0[] = {0x58,0xA9,0x00}

Here is what I wrote so far. printf("%c", ch); shows me what I need but when I uncomment strcat(LR0, ch); it fails at run time with a segment fault. I don't know if I should use strcat or anything else to append the elements of this LR0 array.

#include <stdio.h>                                                                                                                                                                                                   
#include <stdlib.h>                                                                                                                                                                                                  
#include <string.h>                                                                                                                                                                                                  

int main() {                                                                                                                                                                                                         
   int ch;                                                                                                                                                                                                           
   FILE *fp;                                                                                                                                                                                                         
   //const unsigned char LR0 [1024] = "";                                                                                                                                                                            
   const unsigned char LR0 [] = {};                                                                                                                                                                                  
   fp = fopen("test.txt", "r");                                                                                                                                                                                      
   if (fp == NULL)                                                                                                                                                                                                   
   {                                                                                                                                                                                                                 
      perror("Error while opening the file.\n");                                                                                                                                                                     
      exit(EXIT_FAILURE);                                                                                                                                                                                            
   }                                                                                                                                                                                                                 
   while((ch = fgetc(fp)) != EOF){                                                                                                                                                                                   
      printf("%c", ch);                                                                                                                                                                                              
      //strcat(LR0, (char) ch);                                                                                                                                                                                             
   }                                                                                                                                                                                                                 
   fclose(fp);                                                                                                                                                                                                       
   return 0;                                                                                                                                                                                                         
}

Sorry so basic question not able to fix it by googling etc. I am not a C developer and I am using gcc on linux. My text file does not contain lines so I cannot use this solution

gmaxin
  • 43
  • 4
  • 1
    Possible duplicate of [Read .CSV file in C](https://stackoverflow.com/questions/12911299/read-csv-file-in-c) – Gaurav Pathak Sep 17 '18 at 06:53
  • You cannot write to a variable declared as a const in C, so when you are doing `strcat()` on `const unsigned char LR0[]` the program is throwing a segfault. – Gaurav Pathak Sep 17 '18 at 07:01
  • LR0 is declared as 0 length - so when you try to copy to it, you're trying to write to unallocated memory. which causes a segfault – fredrik Sep 17 '18 at 07:14
  • 1
    @Gaurav Yes you can - just case the const away. It's not nice - but in C you actually can. – fredrik Sep 17 '18 at 07:15
  • 1
    @Gaurav I have tried it with by removing `const` but as @fredrik mentioned already it still fails because LR0 is allocated as a 0-length array. Writing to it leads to a segfault. – gmaxin Sep 17 '18 at 07:27
  • @fredrik even with a "just case the const away", it is still UB to write to the `const` array. – chux - Reinstate Monica Sep 17 '18 at 07:38
  • gxmaxin Are you interested in a standard C answer or one that works with your compiler's extensions to the language? – chux - Reinstate Monica Sep 17 '18 at 07:40
  • 1
    @chux thanks for help, I am using `gcc` on my desktop now but in the end I have to cross compile with `arm-poky-linux-gnueabi-gcc` I would prefer standard C but if I that's makes it harder, an gcc option would be enough. – gmaxin Sep 17 '18 at 07:46
  • @chux UB yes, but it is possible and if you know what you're doing yo u can get away with it. – fredrik Sep 17 '18 at 12:44

2 Answers2

2

There are two problems in your code.

  1. LR0 is declared as const with unspecified size which is just pointer, writing to it may result in UB.
  2. strcat needs it arguments as char * type but your second argument is of char type (int ch;).

    strcat(LR0, (char) ch)

You can use the fscanf with , as delimiter as below to read only the hex values discarding ,.

int main() {                                                                                                                                                            
    FILE *fp;                                                                                                                                                            
    unsigned char LR0 [1024] = {};                                                                                                                                          
    fp = fopen("test.txt", "r");                                                                                                                                         
    if (fp == NULL) {                                                                                                                                                                    
        perror("Error while opening the file.\n");                                                                                                                        
        exit(EXIT_FAILURE);                                                                                                                                               
    }

    int i = 0;                                                                                                                                                          
    while(fscanf(fp, "%c,", &LR0[i]) == 1){                                                                                                                                
        printf("%c", LR0[i++]);                                                                                                                                           
    }

    fclose(fp);                                                                                                                                                          
    return 0;                                                                                                                                                            
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
kiran Biradar
  • 12,700
  • 3
  • 19
  • 44
  • 3
    Point 1 is wrong, all you need to do is cast it away. But LR0 is allocated as a 0-length array. Wrinting to is will thus result in a segfault. – fredrik Sep 17 '18 at 07:16
  • @fredrik Updated accordingly. – kiran Biradar Sep 17 '18 at 07:32
  • 1
    "writing to it may result in UB." - it is UB - due to `const`. a "cast way" does not remove the UB-ness of writing - the underlying object is still a `const` array.. It is also UB to write outside the bounds of an array. Yet a 0 length array it outside std C, so we are dealing with a language extension with its rules. – chux - Reinstate Monica Sep 17 '18 at 07:33
1

const unsigned char LR0 [] = {}; implies a zero length array - that is not standard C yet allowed with some compilers.

strcat(LR0, (char) ch); attempts to 1) write to a const array LR0 and 2) write outside the array - it is only 0 length. Both of the are undefined behavior (UB).

I don't know if I should use strcat

Using str...() functions will not well handle input which may contain many "0x00, 0x00, ...".


How I can read a text file with comma separated hex values e.g. 0x58,0xA9,0x00 and put its values as elements of an array (?)

Read the file to determine its length and contents. I suggest a pass for each.

The below is untested, yet hopefully enough to get OP started. It has little error detection.

// Parse a text file like  "0x58,0xA9,0x00"
// Return byte count.  Return 0 on error.
size_t read_comma_hex(FILE *f, unsigned char *dest, size_t num) {
  rewind(f);
  size_t i;
  for (i = 0; i<num; i++) {
    if (i) {
      int ch = fgetc(f);

      // Add to tolerate white space before the ',' or after the the last number
      while (isspace(ch)) {
        ch = fgetc(f);
      }

      if (ch == EOF) break;    // no more data
      if (ch != ',') return 0; // Fail, as ',' expected
    }
    unsigned char hex;
    if (fscanf(f, "0x%hhx", &hex) != 1) return 0;   
    if (dest) dest[i] = hex;
  }
  return i;
}

void read_comma_hex_file(FILE *f) {
  size_t n =  read_comma_hex(f, NULL, SIZE_MAX);
  if (n == 0) return; // no data or failure

  // OP wants an array - research variable length array
  const unsigned char LR0[n];
  // Alternative: allocate memory instead of using an _array_. (not shown)

  // Read data into the array  
  read_comma_hex(f, LR0, n);

  // use LR0 and n some how
  for (size_t i = 0; i<n; i++) {
    printf("0x%02hhX%s", LR0[i], i > 0 ? "," : "");
  } 
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • @gmaxin Given the sample format `"0x58,0xA9,0x00"`, I rejected your suggested edit as it does not detect errors properly. I suspect your desire for the code change was due to wanting to also allow a new format: `"0x58,0xA9,0x00\n"`. I amended the answer to tolerate whitespace at the end. – chux - Reinstate Monica Sep 19 '18 at 15:41