I am trying to separate an IPV6 address from a port in C. The address and port will always be given by "'[' + address + ']:' + port", for example: "[2009:7a4d:80d2:33af:0000:0000]:6667". In python, to do this, I would do something similar to the following:
>>> thing = "[2009:7a4d:80d2:33af:0000:0000]:6667"
>>> print thing[-4:]
6667
>>> print thing[1:30]
2009:7a4d:80d2:33af:0000:0000
How do I do the equivalent of python's right-to-left parsing, i.e. [-4:], in C? And, preferably without using regex, how can I say in C that I would like everything between '[' and ']'?
Thanks for any help and advice!
C does not have string manipulation built into the language, so you need to use a few functions. strrchr() searches for a given character from the end of the string. Here's an example of how to use it:
int main()
{
char* thing = "[2009:7a4d:80d2:33af:0000:0000]:6667";
char* a=strrchr(thing,']'); /* Find the last ']' */
char address[128]; /* Make somewhere new to hold the address part */
strncpy(address, thing+1, a-thing-1); /* copy (a-thing)-1 characters, starting from the second character of thing, into address */
printf("port: %s\n",a+2); /* a+2 is two characters from the start of a (where we found the ']') */
printf("address: %s\n",address);
}
You can also write a '\0' into the string as in SashaN's answer, which effectively divides the original string in two. This won't work here as I used a string constant which can't be modified. Note that 'address' must be long enough to hold the address under all cases.
'a' and 'thing' are both pointers, so (a-thing) is used to give the difference (in characters) between the start of thing and the ']'.
char* thing = "[2009:7a4d:80d2:33af:0000:0000]:6667";
char ipv6[30];
strncpy (ipv6, thing + 1, 29);
ipv6[29] = '\0';
It's crude, and only works with the fixed-string constraints you outlined.
You can use strtok_r for this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *saveptr;
char *address;
char *port;
address = strtok_r(argv[1], "[]", &saveptr);
port = strtok_r(NULL, ":", &saveptr);
puts(port);
return EXIT_SUCCESS;
}
Note that I haven't actually parsed it backwards, but that doesn't seem necessary from the information you provided.
Here is a function that will return the substring between the firstmost and lastmost characters in a string, provided as parameter. The exclusive flag tells it whether or not to include those characters in the result.
I'm guessing some additional validation should be done before attempting strncpy(), so be careful.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *substr_betweenchars(char *string, char begin, char end, int exclusive)
{
char *left = strchr(string, begin);
char *right = strrchr(string, end);
char *result = 0;
int a = left - string;
int b = right - string;
int n = b - a + 1 - (!!exclusive << 1);
if (left && right)
{
result = malloc(n * sizeof(char));
strncpy(result, left + !!exclusive, n);
}
return result;
}
int main(void)
{
char string[] = "[2009:7a4d:80d2:33af:0000:0000]:6667";
printf("%s\n", substr_betweenchars(string, '[', ']', 1));
printf("%s\n", substr_betweenchars(string, '[', ']', 0));
printf("%s\n", substr_betweenchars(string, '8', '2', 1));
printf("%s\n", substr_betweenchars(string, '8', '2', 0));
return 0;
}
Output:
$ gcc -Wall -o substr substr.c
$ ./substr
2009:7a4d:80d2:33af:0000:0000
[2009:7a4d:80d2:33af:0000:0000]
0d
80d2
Would you consider using sscanf() here like a regex? It has a regex-like feature that could read the address from the formatted string quite nicely:
char str[] = "[2009:7a4d:80d2:33af:0000:00000]:6667";
char addr[30];
sscanf(str, "[%29[^]]]", addr);
addr[29] = '\0';
printf("%s", addr); /* 2009:7a4d:80d2:33af:0000:0000 */
Otherwise you could just scan through the string looking for the open and close brackets and copy the contents in between as some of the other answers have shown.
man string(3C)
portstr = strrchr(ipv6str, ':');
if (portstr != NULL) {
*portstr = '\0';
portstr++;
}
Related
Trying to do Exercise 1-19 of K&R 2nd ed., e.g. writing a function to reverse a string. I thought I managed, but the print output looks strange :-) If I use STRINGSIZE 5 the output is
Original String: hello
Reversed String: ollehhello. If I use STRINGSIZE 6 to keep in mind the '\0' string end character and modify the while-loop to while ((outputString[STRINGSIZE - (i + 2)] = inputString[i]) != '\0'), then I get Original String: hello
Reversed String: olleh?hello, I guess the ? is some random character coming from a '\0' added to the reversed string in the while-loop at position 5; but hello is again added. Could anyone explain how come hello gets added to the end of olleh and how can I get rid of it so that I only get the proper reversed string ?
Here is the code:
#include <stdio.h>
#define STRINGSIZE 5
void reverseString (char inputString[], char outputString[]);
int main(void) {
char stringToReverse[] = "hello";
char reversedString[STRINGSIZE];
reverseString(stringToReverse, reversedString);
printf("Original String: %s\nReversed String: %s\n", stringToReverse, reversedString);
}
void reverseString (char inputString[], char outputString[]) {
int i;
i = 0;
while ((outputString[STRINGSIZE - (i + 1)] = inputString[i]) != '\0')
++i;
}
First, the character array reversedString[] does not have enough space to store the null terminator of the string "hello". One option is to use a variable length array here:
char reversedString[strlen(stringToReverse) + 1];
VLAs were introduced in C99, and made optional in C11. As I remember it, K&R does not include coverage of variable length arrays, since even the 2nd edition was published before this.
Another option that would be compatible with C89 is to use the sizeof operator:
char stringToReverse[] = "hello";
char reversedString[sizeof stringToReverse];
Here, the result from the sizeof operator is known at compile time, and can be used in the declaration of a fixed size array. This size includes space for the null terminator, in contrast to the result from strlen("hello"). Note that this would not work with char *stringToReverse = "hello";, since then the sizeof operator would give the size of a pointer. This also would not work if stringToReverse had been passed into a function first, since then the array name would have decayed to a pointer to the first element of stringToReverse.
In the reverseString() function, the length of inputString needs to be determined (since STRINGSIZE is no longer being used); this can be done with strlen(), or in a loop. Then, critically, the function must be certain to add a null terminator (\0) to outputString[] before returning. Also note that a return statement has been added to the end of main() to make this truly C89 compatible:
#include <stdio.h>
void reverseString (char inputString[], char outputString[]);
int main(void) {
char stringToReverse[] = "hello";
char reversedString[sizeof stringToReverse];
reverseString(stringToReverse, reversedString);
printf("Original String: %s\nReversed String: %s\n",
stringToReverse, reversedString);
return 0;
}
void reverseString(char inputString[], char outputString[])
{
int length = 0;
int i = 0;
/* Get inputString length; or use strlen() */
while (inputString[length] != '\0') {
++length;
}
/* Copy to outputString[] in reverse */
while (i < length) {
outputString[i] = inputString[(length - i) - 1];
++i;
}
/* Add null terminator */
outputString[i] = '\0';
}
First I'll suggest that you change this line:
char reversedString[STRINGSIZE];
to
char reversedString[strlen(stringToReverse) + 1]; // + 1 to make room for the string termination
Then I would do something like:
void reverseString (char inputString[], char outputString[]) {
int i;
int len = strlen(inputString);
for(i=0; i<len; ++i)
{
outputString[len-i-1] = inputString[i];
}
outputString[len] = '\0'; // Terminate the string
}
The question is simple but the C language doesn't provide us with a useful library:
Suppose that we have this string:
char *request = "GET /websiteos/example_of_a_simple_html_page.htm HTTP/1.1\r\n";
How can I get the following string:
/websiteos/example_of_a_simple_html_page.htm
The string I’m looking for is found between 2 spaces. The problem is that each time I will have a new request line, so I don't know the size of the string.
I thought I'd proceed like this, but it doesn't work:
char * getTheResource(char *request){
char c;
int i=4;
char *resource=(char *)malloc(20);
while (request[i] != ' ')
{ strcat(resource, request[i]);
i++;
}
return resource;
}
int main( int n , char *arg[] )
{
char *request = "GET /websiteos/example_of_a_simple_html_page.htm HTTP/1.1\r\nHost: help.websiteos.com\r\n\r\n";
char *res =getTheResource(request);
printf("the ressource is :%s\n",res);
}
I'm getting a compilation error:
In function ‘getTheResource’:
example.c:19:3: warning: passing argument 2 of ‘strcat’ makes pointer from integer without a cast [enabled by default]
strcat(resource, request[i]);
So how can I solve this problem?
Consider using strchr function to find pointer to first space in your string, then pass this pointer increased by one to strchr again to get pointer to second space in your string, then copy the range from first pointer to second into output and add a null terminator.
#include <string.h>
#include <stdio.h>
void f(const char* s, char* res) {
char* l = strchr(s, ' ');
char* r = strchr(l + 1, ' ');
memcpy(res, l + 1, r - l);
res[r - l - 1] = '\0';
}
int main() {
const char* s = "sdfasdfasdf sadf sdfasdf";
char res[1024];
f(s, res);
printf("%s\n", res);
return 0;
}
strcat(resource, request[i]);
It is wrong because request[i] is of type char and strcat require char * .
You can assign character to resource at that index using = operator instead:
int j = 0;
while(request[i] != ' ' && j < 19){ // Or the size you allocate to your pointer
resource[j] = request[i];
i++;
j++;
}
resource[j] = '\0';
EDIT-
You can also make use of strtok. Use space as delimiter and get the string you want after tokenizing (But declare request as char request[] = "your string"; in main).
You have several problems with your code.
The strcat should not be used for copying a single character, use assignment instead.
You should always check the return from your allocations - in this case use calloc() instead of malloc() so the buffer gets initialized with NUL characters as well as allocated.
Your while loop is very dangerous as it assumes the string has at least one ' '. You should make sure to always check so you don't run off the end of your string.
If the request string is too short you will have trouble so check for the length of the input string.
You must ensure that you have enough space to hold the new string and not to overrun the new string buffer. So you need a #define to tell you how much you can fit into the new buffer.
Keep in mind that if you use the getTheResource() you must free() the memory if you are not planning on exiting the application. It is not required here because you are exiting the application but in case you use the getTheResource() somewhere else in your code you should free the returned buffer when done with it.
It is good practice to free() your memory anyway because it will help you discover errors that you didn't expect - like overrunning the resource string buffer length might not show up as an error unless you try to free the buffer and then the OS complains. Something that will get you later after you think everything is running OK (but it isn't).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NEW_STRING_MAX_SIZE 100
char *getTheResource(char *request) {
int i=4, j=0;
char *resource;
// validate input string is not NULL
if ( !request )
return NULL;
// allocate and initialize buffer to hold new string
if ( !( resource = (char *)calloc(1, NEW_STRING_MAX_SIZE) ) )
return NULL;
// validate input string is at least 4-characters
if ( strlen( request ) <= i )
return resource;
// loop through old string copying to new string char by char
while ( request[i] != '\0' && request[i] != ' ' && j < NEW_STRING_MAX_SIZE-1 )
resource[j++] = request[i++]; // do a character assignment rather than strcat
return resource;
}
int main( int n , char *arg[] )
{
char *request = "GET /websiteos/example_of_a_simple_html_page.htm HTTP/1.1\r\nHost: help.websiteos.com\r\n\r\n";
char *res = getTheResource(request);
printf("the ressource is :%s\n",res);
if ( res != NULL )
free( res );
}
I want to insert characters into the middle of a char array in C, but first I want to shift it to the right each time prior to adding a char so that I don't lose what's already in the char array (called input) by overwriting.
I assume you are terminating the array with a null char since you are using strlen. In that case, I'm pretty sure the first iteration of your for loop will overwrite the null character with the preceding char, and you don't seem to replace it. Try running
for( k = strlen(input) + 1; k > place42; k--)...
This should replace your null character so that your array is properly terminated. Of course you should also be sure you are not overflowing your array and writing on memory that doesn't belong to you.
Why not a write a generic insert routine using the standard C string functions? Something like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// insert "ins" into "src" at location "at"
char *insert(char *src, char *ins, int at) {
char dst[strlen(src) + strlen(ins) + 1];
strncpy(dst, src, at);
strcpy(dst + at, ins);
strcpy(dst + at + strlen(ins), src + at);
return strdup(dst);
//return strcpy(src, dst); // you could return this if you know src is long enough
}
int main(void) {
char *src = "abcdef";
char *ins = "123";
printf("%s\n", insert(src, ins, 3));
return 0;
}
prints
abc123def
I have a character pointer that points the begining of a string and an index less than the length of the string. Now I want to create a pointer to point a substring of original string from the begining to the index or a substring with above constraints. Please help me to find a way to get it done. Here is a bit of the code:
char* ch="323+465";//this is the original string
int index=2; //this is the index upto which I wish to create a substring,
// in java, it would have been ch.substring(0,3), if ch were a String
Thanks in advance.
You can't do that without creating 3 strings. The char point only marks the beginning of the string, so you would need to combine a pointer and an index into a new type. Remember you don't have strings in C. In languages like Java (and others) will create copies of the sub string anyway.
struct pseudo_string { char *s, int index; } vstring[3];
char* ch="323+465";
vstring[0].s = ch;
vstring[0].index = 2;
vstring[1].s = ch + index + 1; // weird
vstring[1].index = 1;
vstring[2].s = vstring[1].s + 1;
vstring[2].index = 2;
So it is overly complex and useless. In this case index is being used as counter...
If you want to keep the same base pointer, you gonna need 2 indices or 1 index and a len:
struct pseudo_string2 { char *s; int start; int end; };
But that's an overkill for small strings.
If don't want to use malloc, you can try to use a matrix:
char vstring[3][10]={0};
strncpy(vstring[0], ch, 3);
strncpy(vstring[1], ch+3, 1);
strncpy(vstring[2], ch+4, 3);
The advantage of the matrix, even if you waste few bytes, is that you don't need to deallocate it. But if you need to use these values outside this function, than you don't have another scape than to use malloc and free (don't consider globals for that ;-).
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char * substr(char *s, int start, int end)
{
int size = end - start + 2; // 1 for the inclusive limits and another 1 for the \0
char * r = (char*)malloc(size);
strncpy(r,s+start, size-1);
r[size-1]=0;
return r;
}
int main()
{
char* ch="323+465";
char *parts[3];
parts[0] = substr(ch, 0,2);
parts[1] = substr(ch, 3,3);
parts[2] = substr(ch, 4,6);
printf("%s %s %s\n", parts[0], parts[1], parts[2]);
free(parts[0]);
free(parts[1]);
free(parts[2]);
}
Make a copy of a suitable number of characters:
char * substr = malloc(index + 2);
strncpy(substr, ch, index + 1);
substr[index + 1] = 0;
// ...
free(substr);
If you're happy to mutilate the original string, just insert a null byte:
ch[index + 1] = 0;
The odd + 1 comes from the fact that your index seems to be inclusive, which is generally a bad idea.
You can't, because that would imply modifying the string literal, which is illegal.
Alternative:
char ch[]="323+465";
int index=2;
ch[index] = '\0';
First, make the string writable by using a char array instead of a pointer to a string literal. Then
char ch[] = "323+456";
int idx = 2;
ch[idx] = 0; /* Now ch holds the string "32" */
You should avoid an identifier clash with the classic BSD index function, that's why I used idx instead.
This solution assumes it is okay to modify the original string. If not, you need to allocate a new string first.
the same behavior of java substring (allocates new string)
char* res = (char*)malloc(index+2);
strncpy(res,ch,index+1);
res[index+1]='\0';
I see that you try to delimit by +, so easier is to use strtok :
char ch[] ="323+465";
char * res;
res = strtok (ch,"+");
// res= 323
my problem is in convert a char to string
i have to pass to strcat() a char to append to a string, how can i do?
thanks!
#include <stdio.h>
#include <string.h>
char *asd(char* in, char *out){
while(*in){
strcat(out, *in); // <-- err arg 2 makes pointer from integer without a cast
*in++;
}
return out;
}
int main(){
char st[] = "text";
char ok[200];
asd(st, ok);
printf("%s", ok);
return 0;
}
Since ok is pointing to an uninitialized array of characters, it'll all be garbage values, so where the concatenation (by strcat) will start is unknown. Also strcat takes a C-string (i.e. an array of characters which is terminated by a '\0' character). Giving char a[200] = "" will give you a[0] = '\0', then a[1] to a[199] set to 0.
Edit: (added the corrected version of the code)
#include <stdio.h>
#include <string.h>
char *asd(char* in, char *out)
{
/*
It is incorrect to pass `*in` since it'll give only the character pointed to
by `in`; passing `in` will give the starting address of the array to strcat
*/
strcat(out, in);
return out;
}
int main(){
char st[] = "text";
char ok[200] = "somevalue"; /* 's', 'o', 'm', 'e', 'v', 'a', 'l', 'u', 'e', '\0' */
asd(st, ok);
printf("%s", ok);
return 0;
}
strcat will not append single characters. Instead it takes a const char* (a full C-style string) which is appended to the string in the first parameter. So your function should read something like:
char *asd(char* in, char *out)
{
char *end = out + strlen(out);
do
{
*end++ = *in;
} while(*in++);
return out;
}
The do-while loop will include the zero-terminator which is necessary at the end of C-style strings. Make sure that your out string is initialized with a zero-terminator at the end or this example will fail.
And as an aside: Think about what *in++; does. It will increment in and dereference it, which is the very same as in++, so the * is useless.
To look at your code, I can make a couple of pointers in relation to it, this is not a criticism, take this with a pinch of salt that will enable you to be a better C programmer:
No function prototype.
Incorrect usage of pointers
Dealing with the strcat function is used incorrectly.
Overdoing it - no need for the asd function itself!
Usage of dealing with variables notably char array that is not properly initialized.
#include <stdio.h>
#include <string.h>
int main(){
char st[] = "text";
char ok[200];
ok[0] = '\0'; /* OR
memset(ok, 0, sizeof(ok));
*/
strcat(ok, st);
printf("%s", ok);
return 0;
}
Hope this helps,
Best regards,
Tom.
To convert a character to a (null terminated) string you could simply do:
char* ctos(char c)
{
char s[2];
sprintf(s, "%c\0", c);
return s;
}
Working example: http://ideone.com/Cfav3e