0

As said in the title, I would like to save each part of my text in character array contained in my structure called Identity, here is the code:

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

char strExample[]="Andrew;Smith;18;Wall Street;New York;10011;USA";

typedef struct  Identity{
    char firstName[20];
    char lastName[20];
    char age[5];
    char street[64];
    char city[20];
    char postCode[8];
    char country[20];
}Identity;

void textParse()
{
  char *ptr = strExample; 
  char *token;
  int i = 0;
  while ((token= strsep(&ptr,";")) != NULL)
  {
    printf("%s\n",token);
  }
}

int main(int argc, char **argv) {

    textParse();

    return 0;
}

The splitting works well but I don't find how to save every single token in Identity struct. How can I do it?

3
  • 1
    Please change the wording: You are not saving strings in a typedef; you are saving them in a chanacter array contained in a structure. The typedef is just there to name the child. Also you cannot store anything in a type; you can store things in variables. Commented Jan 13, 2021 at 10:40
  • 1
    Do a length check to verify each token fits in the each target char array and then memcpy it there. Commented Jan 13, 2021 at 10:43
  • Yes, I was thinking of doing something like that, but how do you do it with a loop? Commented Jan 13, 2021 at 10:48

2 Answers 2

1

Just define a variable of type Identity, and then use strncpy() to copy each token into the relevant field of the struct:

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

#define STRNCPY_STRUCT_EL(string_field, src) strncpy(string_field, src, sizeof(string_field) - 1 )

char strExample[]="Andrew;Smith;18;Wall Street;New York;10011;USA";

typedef struct  Identity{
    char firstName[20];
    char lastName[20];
    char age[5];
    char street[64];
    char city[20];
    char postCode[8];
    char country[20];
}Identity;

void textParse(Identity *id)
{
  char *ptr = strExample; 
  char *token;
  int i = 0;

  memset(id, 0, sizeof(*id));
  while ((token = strsep(&ptr,";")) != NULL)
  //while ((token = strtok(ptr,";")) != NULL) //I used this in my test
  {
    // ptr = NULL; //I used this in my test, to fit strtok
    switch(i++)
    {
        case 0:
            STRNCPY_STRUCT_EL(id->firstName, token);
            break;
        case 1:
            STRNCPY_STRUCT_EL(id->lastName, token);
            break;
        case 2:
            STRNCPY_STRUCT_EL(id->age, token);
            break;
        case 3:
            STRNCPY_STRUCT_EL(id->street, token);
            break;
        case 4:
            STRNCPY_STRUCT_EL(id->city, token);
            break;
        case 5:
            STRNCPY_STRUCT_EL(id->postCode, token);
            break;
        case 6:
            STRNCPY_STRUCT_EL(id->country, token);
            break;
    }    
  }
}

int main(int argc, char **argv) {
    Identity id;

    textParse(&id);

    printf("Identity:\n%s %s, %s y.o.\nLives in %s, %s (%s - %s)\n",
           id.firstName, id.lastName, id.age, id.street, id.city, id.postCode, id.country);

    return 0;
}
  • Basically I checked the position of the token and then I copied it in the corresponding position of the struct. I used a switch-case. Not so elegant but it works
  • I copied it using a macro that automatically calculates the size of the field. I want to copy size-1 characters as I want to leave room for the string terminator '\0'
  • It works because I previously memseted the whole struct to 0, so that after strncpy the string terminator is for sure where it must be
  • I had to change textParse() signature in order to accept a pointer to Identity. Inside it I skipped sanity checks (for example checks against NULL pointers). I recommend adding them into your final implementation
  • This implementation truncates any token longer than the corresponding Identity field

Output:

Identity:
Andrew Smith, 18 y.o.
Lives in Wall Street, New York (10011 - USA)
Sign up to request clarification or add additional context in comments.

Comments

0

If you want to process it in a loop, you need to have info on the member arrays--their size and offset--accumulated in an array (arrays are most convenient) beforehand:

Example:

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

char strExample[]="Andrew;Smith;18;Wall Street;New York;10011;USA";

typedef struct  Identity{
    char firstName[20];
    char lastName[20];
    char age[5];
    char street[64];
    char city[20];
    char postCode[8];
    char country[20];
}Identity;

void textParse(Identity *Id)
{
  static size_t const sizes[7]={
      sizeof((Identity){0}.firstName),
      sizeof((Identity){0}.lastName),
      sizeof((Identity){0}.age),
      sizeof((Identity){0}.street),
      sizeof((Identity){0}.city),
      sizeof((Identity){0}.postCode),
      sizeof((Identity){0}.country),
  };
  static size_t const array_offsets[7]={
      offsetof(Identity,firstName),
      offsetof(Identity,lastName),
      offsetof(Identity,age),
      offsetof(Identity,street),
      offsetof(Identity,city),
      offsetof(Identity,postCode),
      offsetof(Identity,country),
  };

  char *ptr = strExample;
  char *token;
  for (int i=0; (token= strsep(&ptr,";")) != NULL; i++)
  {
      size_t const size = (size_t)(ptr-token);
      if(size > sizes[i]) return; /*doesn't fit*/
      else memcpy((char*)Id+array_offsets[i], token, size);
  }
}

int main(int argc, char **argv) {

    Identity id; textParse(&id);
    puts("=============");
    puts(id.firstName);
    puts(id.lastName);
    puts(id.age);
    puts(id.street);
    puts(id.city);
    puts(id.postCode);
    puts(id.country);

    return 0;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.