I have a string like:
my age is 22\r\n\r\n and I live in Rostock
and some other strings like:
I like to swim\r\n\r\n .Yesterday I competed with my 2 friends
Now I want to split a string by \r\n\r\n and have it associated with buffer. Here is what I am trying to do:
char buffer[500];
strcpy(buffer, "my age is 22\r\n\r\n and I live in Rostock");
char *p = buffer;
if((p = strchr(p,"\r\n\r\n"))) {
p[strcspn(p,"tock")] = 0; // trying to slice until the end
}
printf("%s", p);
This gives me a warning as I try to compile saying warning: passing argument 2 of ‘strchr’ makes integer from pointer without a cast I could not understand what this meant.
Also what is good way to split this into 2 char buffers?
strchr expects a mere char and not a string for its second parameter. So you can only pass it a single character.
In C a char is a single character and strings are null terminated char arrays.
What you want to do is probably:
char buffer[500] = "my age is 22\r\n\r\n and I live in Rostock"; // directly initialize the char array
const char sep[] = "\r\n\r\n";
char * p = strstr(buffer, sep); // search the separator
if (p) {
*p = '\0'; // null terminate the first part
p += strlen(sep); // make p point to the start of the second part
printf("%s - %s\n", buffer, p);
}
If you really need to purge the initial part from buffer and have it start at the second part, you could do:
for (char *dest = buffer; p<buffer+sizeof(buffer)-1;) { // do not go past end of array
*dest++ = *p++;
if (*p == '\0') break; // stop on first null
}
Related
Why does the below code give Seg. Fault at last line?
char* m=ReadName();
printf("\nRead String %s\n",m); // Writes OK
char* token;
token=strtok(m,'-');
As said, read string prints w/o problem, but why cannot split to tokens?
strtok modifies its first argument, hence it should be modifiable.
Maybe ReadName() returns a pointer to a read-only char array.Can you show us your ReadName() function.
If that is the reason for seg-faullt, you can create a copy of the char array before you pass it to strtok using the strdup function like:
char *copy = strdup(m);
token = strtok(copy,'-');
....
....
free(copy); // free the copy once you are done using it.
token=strtok(m,'-'); should generate a compiler warning because the second parameter of strtok() is a const char * pointing to multiple delimiters, not a single char delimiter:
char *strtok(char *str, const char *delim);
The ASCII code of '-' is 0x2D, so passing it as the second parameter of strtok() will cause strtok() to dereference the address 0x0000002D, which will cause a segfault or access violation on most modern operating systems. To fix this, use a string literal instead of a character literal: token=strtok(m,"-");
There's also the issue of how the return value of ReadName() is allocated, which others have addressed in their answers.
It's impossible to know for sure without knowing what m points to. But the most likely reason is that m is pointing to readonly memory. So you can print it out, but you can't write to it.
strtok writes to the string, so it's faulting, but printf only reads from it, so it isn't.
Try this
char* m=ReadName();
printf("\nRead String %s\n",m); // Writes OK
char temp = m[0];
m[0] = temp; // I'll bet you segfault here.
Its probably because ReadName() return string. So, the assignment makes m const char* and hence, you cannot alter any of its values (modify the string). So, when 'strtok' tries to modify 'm', Segmentation Fault is there
Remedy:
char *m = malloc(sizeof(char)*MAX);
strcpy(m, ReadName());
OR
char *m = strdup(ReadName());
Code below is taken from a BSD licensed string processing library for C, called zString.
https://github.com/fnoyanisi/zString
Looking at the implementation of the function, you can see that strtok() (or in this case zstring_strtok()) relies on a static *char to preserve the last location of the delimiter and actually modifies the original string.
char *zstring_strtok(char *str, const char *delim) {
static char *static_str=0; /* var to store last address */
int index=0, strlength=0; /* integers for indexes */
int found = 0; /* check if delim is found */
/* delimiter cannot be NULL
* if no more char left, return NULL as well
*/
if (delim==0 || (str == 0 && static_str == 0))
return 0;
if (str == 0)
str = static_str;
/* get length of string */
while(str[strlength])
strlength++;
/* find the first occurance of delim */
for (index=0;index<strlength;index++)
if (str[index]==delim[0]) {
found=1;
break;
}
/* if delim is not contained in str, return str */
if (!found) {
static_str = 0;
return str;
}
/* check for consecutive delimiters
*if first char is delim, return delim
*/
if (str[0]==delim[0]) {
static_str = (str + 1);
return (char *)delim;
}
/* terminate the string
* this assignmetn requires char[], so str has to
* be char[] rather than *char
*/
str[index] = '\0';
/* save the rest of the string */
if ((str + index + 1)!=0)
static_str = (str + index + 1);
else
static_str = 0;
return str;
}
This post explains the deifference between char s[] and char *s quite well. So,
char s[]="Test to pass strtok()"; /* this can be passed to strtok() */
char *m="Test to pass strtok()"; /* passing this will result in SIGSEGV */
I have some code here where, given a .txt file whose contents is
find replace pre
pre
cpre
,I want to find every instance of "pre", and append "k" to it. ie the file should become "find replace kpre".
So I first set out to create a string that is the concatenation of k and pre
(assume k and pre are argv[1] and argv[3], respectively)
char appended[1024];
strcpy(appended, argv[1]);
strcat(appended, argv[3]);
printf("appended string is %s", appended); //prints kpre, which is good
char *replaced = replace(buf, argv[3], appended);
//*string is a line in the file
char* replace(char *string, char *find, char *replace) {
char *position;
char temp[1024];
int find_length = strlen(find);
int index = 0;
while ((position = strstr(string, find)) != NULL) {
strcpy(temp, string);
index = position - string;
string[index] = '\0';
strcat(string, replace); //add new word to the string
strcat(string, temp + index + find_length); //add the unsearched
//remainder of the string
}
return string;
}
.................
fputs(replaced, temp);
Checking on the console, appended = "kpre", which is correct, but when the code is run the file looks like
find replace kkkkkkkkkkkkkkkk.....kkkkkkk
kkkkkkkkk......kkkkk
ckkkkk....kkkkk
the k's go on for a while, I cannot see pre when scrolling all the way to the right. I'm having difficulty figuring out why the code doesn't replace
the instance of 'pre' with 'kpre', even when the appended variable appears to be correct. I have a feeling it has to do with the fact that I set a 1024 character for temp, but even then I'm not sure why k was copied so many times.
Here
while ((position = strstr(string, find)) != NULL) {
you are passing string to strstr() function. The strstr() will return the pointer to the first occurrence of find in string. When you replace pre with kpre and calling again strstr(), it is retuning the pointer to the first occurrence of pre in string which is a sub string of replace string. After some iterations of while loop, it will start accessing the string beyond its size which will lead to undefined behavior.
Instead of passing string to strstr(), you should pass pointer to string and after every replace operation, the make the pointer point to after the replaced part of string. Other way is you can traverse the string character by character using pointer instead of using strstr(), like this:
#define BUFSZ 1024
char* replace(char *string, const char *find, const char *replace) {
if ((string == NULL) || (find == NULL) || (replace == NULL)) {
printf ("Invalid argument..\n");
return NULL;
}
char temp[BUFSZ];
char *ptr = string;
size_t find_len = strlen(find);
size_t repl_len = strlen(replace);
while (ptr[0]) {
if (strncmp (ptr, find, find_len)) {
ptr++;
continue;
}
strcpy (temp, ptr + find_len); // No need to copy whole string to temp
snprintf (ptr, BUFSZ - (ptr - string), "%s%s", replace, temp);
ptr = ptr + repl_len;
}
return string;
}
Note that above code is based on the example you have posted in your question and just to give you an idea about how you can achieve your goal without using strstr(). When writing code, take care of the other possibilities as well like, replace is a huge string.
I have the following code in which I'm reading lines from a file and want to save them using a character pointer array. As I'm using one buffer inside my file read loop all my pointers in the character array end up pointing towards the last line read from file as the last line is the one that is currently held in the buffer when the loop terminates. How can I store them such that each pointer in the character array points to different char arrays in the order they were read.
int num_clients_to_start = 0;
char *token1, *token2, *str;
FILE* fp;
char bufr[256];
char testchar[255] = {};
char *start_client[10];
while(fgets(bufr, 256, fp) != NULL){
if(bufr[0] == '#'|| bufr[0] == '\n')
continue;
str = bufr;
token2 = ""; /* initializing an empty token 2 */
for(str = bufr; ;str = NULL){
token1 = strtok(str, " ");
if(strcmp(token2, "client_name") == 0){
sprintf(testchar,"%s", token1);
start_client[num_clients_to_start] = testchar;
num_clients_to_start++;
}
token2 = token1;
if(str == NULL){
break;
}
}//end of for loop
}//end of while loop
printf("client1 = %s client2 = %s client3 = %s",start_client[0],start_client[1],start_client[2]);
My input file is the following:
client_name abc
client_name def
client_name xyz
And print statement outputs:
client1 = xyz
client2 = xyz
client3 = xyz
Note that start_client[0], [1], [2] are all pointers to the last string (readed by fgets)
Use strdup in order to allocate them:
start_client[num_clients_to_start] = strdup(testchar);
As strdup can be an external identifier, use a prototype
#include <string.h>
char *strdup(const char *s);
And don't forget to free() at the end
You assign the same pointer to all entries in the start_client array. The array testchar will get different contents, but the pointer to it will always be the same. You might want to make start_client an array of arrays of char, and copy the string instead.
Like
char start_client[10][256];
And
strcpy(start_client[num_clients_to_start++], token1);
I am new to C and I am trying to split a date/time string into separate variables. However, when I step through the code in gdb line by line, it works, however, when I let it run through normally without breakpoints it seg faults and I can't see why.
Below is the code:
char * dateTimeString = "2011/04/16 00:00";
char dateVar[11];
char timeVar[6];
if (splitTimeAndDateString(dateVar, timeVar, dateTimeString))
{
exit(1);
}
printf("Date: %s\tTime: %s\n", dateVar, timeVar);
Below is the function
int splitTimeAndDateString(char date[11], char time[6], char * dateString)
{
char *token;
token = strtok(dateString, " ");
int i = 0;
while (token != NULL)
{
if (i == 0)
{
strcpy(date, token);
}
else if (i == 1)
{
strcpy(time, token);
}
else
{
printf("Overrun date time string\n");
return 1;
}
token = strtok(NULL, " ");
i++;
}
return 0;
}
Thanks for any help you can provide.
The strtok() function modifies string that you wants to parse, and replace all delimiters with \0 nul symbol.
Read: char * strtok ( char * str, const char * delimiters );
str
C string to truncate.
Notice that the contents of this string
are modified and broken into smaller strings (tokens). Alternativelly,
a null pointer may be specified, in which case the function continues
scanning where a previous successful call to the function ended.
In your code:
strtok(dateString, " ");
^
| is a constant string literal
dateString points to "2011/04/16 00:00" a constant string literal, and by using strtok() your code trying to write on read-only memory - that is illegal and this caused segmentation fault.
Read this linked answer for diagram to understand: how strtok() works?
Edit:
#: char * strtok ( char * str, const char * delimiters ); In given code example, str is an array, not constant string literal. Its declaration:
char str[] ="- This, a sample string.";
Here str[] is an nul terminated array of chars, that initialized with string and its length is equals to size of the assigned string. You can change the content of str[] e.g. str[i] = 'A' is a valid operation.
Whereas in your code:
char * dateTimeString = "2011/04/16 00:00";
dateTimeString is pointer to string literal that is not modifiable e.g dateTimeString[i] = 'A' is an illegal operation this time.
Alright, so I have the following code:
char** args = (char**)malloc(10*sizeof(char*));
memset(args, 0, sizeof(char*)*10);
char* curToken = strtok(string, ";");
for (int z = 0; curToken != NULL; z++) {
args[z] = strdup(curToken);
curToken = strtok(NULL, ";")
}
I want every arg[z] casted into an array of chars -- char string[100] -- and then processed in the algorithms I have following. Every arg[z] needs to be casted to the variable string at some point. I am confused by pointers, but I am slowly getting better at them.
EDIT:
char string[100] = "ls ; date ; ls";
arg[0] will be ls, arg[1] will be date, and arg[2] will be ls after the above code.
I want to put each argument back into char string[100] and process it through algorithms.
one easiest way is to keep a backup of the original string in some temporary variable.
char string[100] = "ls ; date ; ls";
char temp_str[100] = {0};
strcpy (temp_str, string);
Another way is to do it by strcat. z has the number of agruments.
memset(string, '\0', 100);
for (i = 0; i < z; i++)
{
strcat(string, args[i]);
if (i != (z - 1))
{
//if it is last string dont append semicolon
strcat(string, ";");
}
}
Note : Take care of the boundary condition check
If you want the parts of string copied into a fixed length string[100] then you need to malloc 100 chars for each args[] inside the loop and strncpy() the result of strtok into it. strdup will only allocate enough memory for the actual length of the supplied string (plus \0)
This:
char** args = (char**)malloc(10*sizeof(char*));
memset(args, 0, sizeof(char*)*10);
is broken code. First, you shouldn't cast malloc()'s return value. Second, args is a pointer to ten pointers to char. You can't set them to NULL using memset(), there's no guarantee that "all bytes zero" is the same as NULL. You need to use a loop.