0

I'm on an MCU with extremely limited space, and I'm somehow losing my reference in C. I want the format of something like this:

int commandsubstring(char *stringaddress,char *substringaddress);

However, I did this routine in ASM because I was having some issue in C and just wanted to get it done. Now that it's done, I want to fix it. What the function does is read a SCPI command. I take the format of "MEASure:VOLTage:DC?" and then I recursively return the command. In my example, want to return the address of substring

 MEASure:VOLTage:DC?
 ^       ^ 

I want to be able to do something like :

char *cmd="MEASure:VOLTage:DC?";
char *subcmd;
commandsubstring(cmd, subcmd);
printf("%s\n", cmd);
printf("%s\n", subcmd);

And then get the result of

 MEASure:VOLTage:DC?
 VOLTage:DC?

I'm unsure why, but I'm losing my pointer somewhere in the process. In the rest of the code, I just return structures, but due to the fact that this particular part is recursive, I wanted to try something that I felt was safer, but I just cannot seem to get the C correct and it's just a braino somewhere. Any assistance would be greatly appreciated.

Edit This is not a question about tokenization, just the proper way to correctly return a different location in the same string.

3
  • So, you have working assembly that you need writing in C? If that's the case, I think you will need to either post the assembly or paraphrase it as pseudocode Commented Oct 18, 2018 at 13:02
  • The first thing you need to learn is to tokenize a string. The second thing you need to learn is how to emulate pass by reference in C. Commented Oct 18, 2018 at 13:03
  • No need to write this in assembly. That makes the thing much more difficult. Commented Oct 18, 2018 at 13:08

4 Answers 4

2

Maybe this example will help :

#include <stdio.h>

int commandsubstring(char *stringaddress,char **substringaddress)
{
    char * ptr = stringaddress;
    while (ptr!=0) {
        if ((*ptr)==':') { 
            *substringaddress = ptr+1; 
            break;
        }
        ptr++;
    }
    return 0;
}

int main()
{
    char *cmd="MEASure:VOLTage:DC?";
    char *subcmd;
    commandsubstring(cmd, &subcmd);
    printf("%s\n", cmd);
    printf("%s\n", subcmd);

    return 0;
}
Sign up to request clarification or add additional context in comments.

1 Comment

Why not just use strchr()?
2

When you do this:

char *cmd="MEASure:VOLTage:DC?";
char *subcmd;
commandsubstring(cmd, subcmd);

You're passing the value of subcmd to the function. Inside the function, it's probably assigning a value to the named parameter which doesn't change the variable in the calling function.

The cleanest way to handle this is to remove the second parameter and return the pointer in question, assigning it to subcmd:

char *commandsubstring(char *stringaddress);

...

subcmd = commandsubstring(cmd);

Comments

1

Looking at the declaration you provide and usage example, I'd say you need a pointer-to-a-pointer as the second argument. What you have is a pointer-to-char.

What you have looks much like an undefined behaviour:

/* Takes two pointer by value */
int commandsubstring(char *stringaddress,char *substringaddress);

void foo(void) 
{
   char *cmd="MEASure:VOLTage:DC?";
   char *subcmd;                  /* an uninitialized variable, could be anything */
   commandsubstring(cmd, subcmd); /* you pass an uninitilized variable in */
   printf("%s\n", cmd);
   printf("%s\n", subcmd);        /* you use an uninitialized variable. Nothing has changed it since it was declared. */
}

Your request for "the proper way to correctly return a different location in the same string" sounds to me like "the way to correctly return a pointer to char in the same string". There are two ways: you can either make use of return value, or make use of the OUT-parameter.

Imagine it's not char *, imaging you want an int from some function. Here are you "int" options:

/* You want (int) from you functions */
int use_int_return_value(void);
void use_int_out_parameter(int *pint_to_result);

/* You want (char *) from you functions */
char * use_pchar_return_value(void);
void use_pchar_out_parameter(char ** pchar_to_result);

Comments

1

Assuming the sub-command is identified by the 1st : you could do it like this:

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

int main(void)
{
  const char * cmd = "MEASure:VOLTage:DC?";
  puts(cmd);
  const char * subcmd = strchr(cmd, ':');
  if (NULL == subcmd || !*(++subcmd))
  {
    fprintf(stderr, "No sub-command found.\n");
  }
  else
  {
    puts(subcmd);
  }
}

To have this as a function do

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

const char * find_subcmd(const char * cmd)
{
  assert(NULL != cmd);

  char * subcmd = strchr(cmd, ':');
  return (NULL == subcmd || !*(++subcmd)) ?NULL :subcmd;
}

int main(void)
{
  const char * cmd = "MEASure:VOLTage:DC?";
  puts(cmd);
  const char * subcmd = find_subcmd(cmd);
  if (NULL == subcmd)
  {
    fprintf(stderr, "No sub-command found.\n");
  }
  else
  {
    puts(subcmd);
  }
}

or

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

int find_subcmd(const char * cmd, char const ** psubcmd )
{
  assert(NULL != cmd);
  assert(NULL != psubcmd);

  char * subcmd = strchr(cmd, ':');
  *psubcmd = (NULL == subcmd || !*(++subcmd)) ?NULL :subcmd;

  return *psubcmd ?0 :-1;
}

int main(void)
{
  const char * cmd = "MEASure:VOLTage:DC?";
  const char * subcmd = NULL;
  puts(cmd);
  if (-1 == find_subcmd(cmd, &subcmd))
  {
    fprintf(stderr, "No sub-command found.\n");
  }
  else
  {
    puts(subcmd);
  }
}

Please note that in any of the solutions above subcmd is just pointing "into" what is pointed to by cmd. No data is copied.

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.