Austin
Austin

Reputation: 7339

C setting string equal to substring

In C, If I have:

char *reg = "[R5]";

and I want

char *reg_alt = "R5" (equal to the same thing, but without the brackets), how do I do this?

I tried

*char reg_alt = reg[1:2];

but this doesn't work.

Upvotes: 11

Views: 1715

Answers (4)

Dai
Dai

Reputation: 155438

When using null-terminated strings (the default in C), you can indeed cheaply create a substring of another string by simply changing the starting character pointer, but you cannot make the new substring have a different null-terminator.

An option is to use a Pascal-string library. Pascal-strings are length-prefixed instead of C-strings which are null-terminated, which means Pascal-strings can share contents of a larger string buffer and substring generation is cheap (O(1)-cheap). A Pascal string looks like this:

struct PString {
    size_t length;
    char*  start;
}

PString substring(const PString* source, size_t offset, size_t length) {
    // Using C99 Designated Initializer syntax:
    return PString { .length =  length, .start = source.start + offset };
}

The downside is that most of the C library and platform libraries use null-terminated strings and unless your Pascal-string ends in a null character you'll need to copy the substring to a new buffer (in O(n) time).

Of course, if you're feeling dangerous (and using mutable character buffers) then you can hack it to temporarily insert a null-terminator, like so:

struct CStr {
    char* start;
    char* end;
    char  temp;
}

CStr getCStr(PString* source) {
    char* terminator = (source.start + source.length);
    char previous = *terminator;
    *terminator = '\0';
    return CStr { .start = source.start, .end = terminator, .temp = previous };
}

void undoGetCStr(CStr cstr) {
    *cstr.end = cstr.temp;
}

Used like so:

PString somePascalString = doSomethingWithPascalStrings();
CStr temp = getCStr( somePascalString );
printf("My Pascal string: %s", temp.start ); // using a function that expects a C-string
undoGetCStr( temp );

...which then gives you O(1) PString-to-CString performance, provided you don't care about thread-safety.

Upvotes: 3

Peter
Peter

Reputation: 36616

I suggest you need to read a basic text on C, rather than assuming techniques from other languages will just work.

First, char *reg = "[R5]"; is not a string. It is a pointer, that is initialised to point to (i.e. its value is the address of) the first character of a string literal ("[R5]").

Second, reg_alt is also a pointer, not a string. Assigning to it will contain an address of something. Strings are not first class citizens in C, so the assignment operator doesn't work with them.

Third, 1:2 does not specify a range - it is actually more invalid syntax. Yes, I know other languages do. But not C. Hence my comment that you cannot assume C will allow things it the way that other languages do.

If you want to obtain a substring from another string, there are various ways. For example;

  char substring[3];
  const char *reg = "[R5]";    /* const since the string literal should not be modified */

  strncpy(substring, &reg[1], 2);     /* copy 2 characters, starting at reg[1], to substring */
  substring[2] = '\0';     /*  terminate substring */

  printf("%s\n", substring);

strncpy() is declared in standard header <string.h>. The termination of the substring is needed, since printf() %s format looks for a zero character to mark the end.

Upvotes: 13

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726809

There is no built-in syntax for dealing with substrings like that, so you need to copy the content manually:

char res[3];
memcpy(res, &reg[1], 2);
res[2] = '\0';

Upvotes: 15

Dinorah Tovar
Dinorah Tovar

Reputation: 488

Need to be a char?

Because that only work when is a "string" So maybe you need this

char reg[] = "[R5]";

Then you can do the other thing or just split the string like this question

Upvotes: 1

Related Questions