I have a C string that looks like "Nmy stringP"
, where N and P can be any character. How can I edit it into "my string"
in C?
views:
855answers:
3
+6
A:
To "remove" the 1st character point to the second character:
char mystr[] = "Nmy stringP";
char *p = mystr;
p++; /* 'N' is not in `p` */
To remove the last character replace it with a '\0'
p[strlen(p)-1] = 0; /* 'P' is not in `p` (and it isn't in `mystr` either) */
pmg
2009-11-13 00:10:21
This may not work because by initializing "Nmy stringP" as a literal, the compiler/linker can place it in read only memory, causing the edit to fail.
Suppressingfire
2009-11-13 00:14:18
@Suppressingfire: "Nmy stringP" is indeed a literal string, but it is copied (char by char) to the array `mystr`. The array `mystr` is modifiable.
pmg
2009-11-13 00:17:25
@pmg: Where are you copying? `char *p = mystr` points `p` to `mystr`, it doesn't copy `mystr`.
quark
2009-11-13 00:23:03
@pmg: May I recommend `strdup`?
quark
2009-11-13 00:23:48
The literal string is copied to the location of the variable named "mystr". mystr is _not_ a pointer to the literal, it's a copy of the literal.
Bryan Oakley
2009-11-13 00:26:00
@Bryan Oakley: `mystr` points to the literal array, but that array can be in read-only memory, no?
quark
2009-11-13 00:29:08
`strdup()` is not a Standard function. Its workings, on those implementations that offer it as an extension, may be different from implementation to implementation. I prefer to `malloc()` and `strcpy()` when needed. It wasn't needed to demonstrate how to remove the first and last chars of a string.
pmg
2009-11-13 00:32:23
mystr is not a pointer, it is an array initialized with the contents of a string literal. The code he has is correct.
Brian R. Bondy
2009-11-13 00:32:34
char sz[] = "hello";You will have sizeof(sz) == 6, NOT sizeof(sz) == 4.
Brian R. Bondy
2009-11-13 00:33:46
@pmd: Re: `strdup` vs. `malloc` and `strcpy`: noted.
quark
2009-11-13 00:40:51
@pmd and others: What was confusing me is that pmd uses "copy". What I assume you mean is that the string is laid out on the stack, not in static (possibly read-only) memory. I had forgotten that.
quark
2009-11-13 00:41:46
@quark: doing `char arr[] = "hi";` is the same as `char arr[3]; arr[0] = 'h'; arr[1] = 'i'; arr[2] = '\0';`
pmg
2009-11-13 00:41:50
@Brian R. Bondy: No mystr is not a pointer but it refers to the start of the array anyway. The issue isn't the size of the array (which the compiler can tell you, regardless of where the array was allocated), it was what kind of memory it was allocated it.
quark
2009-11-13 00:43:05
@pmd: Right. I'm used to making string literals `const` and making them global, rather than making them local. Local arrays go on the stack, and I'd forgotten that. Sorry for the quibbling.
quark
2009-11-13 00:44:38
It doesn't matter if it's global or not. `char arr[] = "foo";` copies the elements of the string literal (char by char: 'f', 'o', 'o', and '\0') to the array `arr`. It matters when you have pointers: `char *arr = "foo";` no copying here, whether it's a global or not.
pmg
2009-11-13 00:48:05
Just thought I'd throw `char arr[] = { 'f', 'o', 'o', '\0' };` into the mix for good measure, kinda solidifies the initialization part. Thanks.
James Morris
2009-11-13 01:17:22
A:
The most efficient way:
//Note destroys the original string by removing it's last char
// Do not pass in a string literal.
char * getAllButFirstAndLast(char *input)
{
int len = strlen(input);
if(len > 0)
input++;//Go past the first char
if(len > 1)
input[len - 2] = '\0';//Replace the last char with a null termination
return input;
}
//...
//Call it like so
char str[512];
strcpy(str, "hello world");
char *pMod = getAllButFirstAndLast(str);
The safest way:
void getAllButFirstAndLast(const char *input, char *output)
{
int len = strlen(input);
if(len > 0)
strcpy(output, ++input);
if(len > 1)
output[len - 2] = '\0';
}
//...
//Call it like so
char mod[512];
getAllButFirstAndLast("hello world", mod);
The second way is less efficient but it is safer because you can pass in string literals into input. You could also use strdup for the second way if you didn't want to implement it yourself.
Brian R. Bondy
2009-11-13 00:17:25
The problem I see with your second implementation is that you need to make sure your output is large enough to handle the copy before you call getAllBufFirstAndLast(). In this case, I would recommend adding an outputLength variable to the call and let the called function manipulate output with strn* functions.
shank
2009-11-13 14:10:01
+2
A:
Another option, again assuming that "edit" means you want to modify in place:
void topntail(char *str) {
size_t len = strlen(str);
assert(len >= 2); // or whatever you want to do with short strings
memmove(str, str+1, len-2);
str[len-2] = 0;
}
This modifies the string in place, without generating a new address as pmg's solution does. Not that there's anything wrong with pmg's answer, but in some cases it's not what you want.
Steve Jessop
2009-11-13 01:55:27