In C how can I separate a char array by a delimiter? Or is it better to manipulate a string? What are some good C char manipulation functions?
#include<string.h>
#include<stdio.h>
int main()
{
char input[16] = "abc,d";
char *p;
p = strtok(input, ",");
if(p)
{
printf("%s\n", p);
}
p = strtok(NULL, ",");
if(p)
printf("%s\n", p);
return 0;
}
you can look this program .First you should use the strtok(input, ",").input is the string you want to spilt.Then you use the strtok(NULL, ","). If the return value is true ,you can print the other group.
Look at strtok(). strtok() is not a re-entrant function.
strtok_r() is the re-entrant version of strtok(). Here's an example program from the manual:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *str1, *str2, *token, *subtoken;
char *saveptr1, *saveptr2;
int j;
if (argc != 4) {
fprintf(stderr, "Usage: %s string delim subdelim\n",argv[0]);
exit(EXIT_FAILURE);
}
for (j = 1, str1 = argv[1]; ; j++, str1 = NULL) {
token = strtok_r(str1, argv[2], &saveptr1);
if (token == NULL)
break;
printf("%d: %s\n", j, token);
for (str2 = token; ; str2 = NULL) {
subtoken = strtok_r(str2, argv[3], &saveptr2);
if (subtoken == NULL)
break;
printf(" --> %s\n", subtoken);
}
}
exit(EXIT_SUCCESS);
}
Sample run which operates on subtokens which was obtained from the previous token based on a different delimiter:
$ ./a.out hello:word:bye=abc:def:ghi = :
1: hello:word:bye
--> hello
--> word
--> bye
2: abc:def:ghi
--> abc
--> def
--> ghi
One option is strtok
example:
char name[20];
//pretend name is set to the value "My name"
You want to split it at the space between the two words
split=strtok(name," ");
while(split != NULL)
{
word=split;
split=strtok(NULL," ");
}
You could simply replace the separator characters by NULL characters, and store the address after the newly created NULL character in a new char* pointer:
char* input = "asdf|qwer"
char* parts[10];
int partcount = 0;
parts[partcount++] = input;
char* ptr = input;
while(*ptr) { //check if the string is over
if(*ptr == '|') {
*ptr = 0;
parts[partcount++] = ptr + 1;
}
ptr++;
}
Note that this code will of course not work if the input string contains more than 9 separator characters.
I came up with this.This seems to work best for me.It converts a string of number and splits it into array of integer:
void splitInput(int arr[], int sizeArr, char num[])
{
for(int i = 0; i < sizeArr; i++)
// We are subtracting 48 because the numbers in ASCII starts at 48.
arr[i] = (int)num[i] - 48;
}
This is how I do it.
void SplitBufferToArray(char *buffer, char * delim, char ** Output) {
int partcount = 0;
Output[partcount++] = buffer;
char* ptr = buffer;
while (ptr != 0) { //check if the string is over
ptr = strstr(ptr, delim);
if (ptr != NULL) {
*ptr = 0;
Output[partcount++] = ptr + strlen(delim);
ptr = ptr + strlen(delim);
}
}
Output[partcount++] = NULL;
}
In addition, you can use sscanf for some very simple scenarios, for example when you know exactly how many parts the string has and what it consists of. You can also parse the arguments on the fly. Do not use it for user inputs because the function will not report conversion errors.
Example:
char text[] = "1:22:300:4444:-5";
int i1, i2, i3, i4, i5;
sscanf(text, "%d:%d:%d:%d:%d", &i1, &i2, &i3, &i4, &i5);
printf("%d, %d, %d, %d, %d", i1, i2, i3, i4, i5);
Output:
1, 22, 300, 4444, -5
For anything more advanced, strtok() and strtok_r() are your best options, as mentioned in other answers.
Related
Situation as following:
In the first line input a string, then the following lines are 'command'. 2 types of command 'p' and 's', 'p' means printing the string, 's' means substitution.
e.g. Input a string aaabbbcccqwerdd then input sbqwerbkkk
(s means substitution, b acts as a delimiter, therefore it means replacing qwer in the string with kkk)
The expected result should be aaabbbccckkkdd, but instead I got aaabbbccckkkrdd
Any help?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLEN 1023
int main() {
char str[MAXLEN];
scanf("%s", str);
char command[MAXLEN];
while (scanf("%s", command) != EOF) {
if (command[0] == 'p') {
printf("%s\n", str); }
else if (command[0] == 's') {
char delimiter[] = {"0"};
strncpy(delimiter, command+1, 1);
char *a = command;
a = strtok(command, delimiter);
a = strtok(NULL, delimiter);
char *b = command;
b = strtok(NULL, delimiter);
int alength = strlen(a);
int blength = strlen(b);
char *bereplaced = strstr(str, a);
if (bereplaced == NULL) {
continue; }
int aindex = bereplaced - str;
strncpy(str + aindex, b, blength);
}
}
return 0;
}
Many things can go wrong here but the main issue is copying from from source string on to itself, there can be memory overlap. Instead declare a new buffer for the result for find/replace operation.
You can define a separate find_replace function as follows:
char* find_replace(const char* src, const char* find, const char* replace)
{
if (!src) return NULL;
char* find_ptr = strstr(src, find); if (!find_ptr) return NULL;
int find_start = find_ptr - src;
int find_length = strlen(find);
char* result = malloc(strlen(src) + strlen(replace) + 1);
strncpy(result, src, find_start);
strcpy(result + find_start, replace);
strcat(result, find_ptr + find_length);
return result;
}
int main()
{
char source[] = "aaabbbcccqwerdd";
char command[] = "sbqwerbkkk";
if (command[0] != 's') return 0;
char delimiter[] = { "0" };
delimiter[0] = command[1];
char* find = strtok(command, delimiter); if (!find) return 0;
find = strtok(NULL, delimiter); if (!find) return 0;
char* replace = strtok(NULL, delimiter); if (!replace) return 0;
char* result = find_replace(source, find, replace);
if (!result) return 0;
printf("%s\n", result);
free(result);
return 0;
}
Here is another solution. It does the substitution directly into the input string by:
Use memmove to move the trailing part of the orginal string to its final location
Use strncpy to copy the substitute substring to its final location
Like:
#include <stdio.h>
#include <string.h>
#define MAXLEN 1023
int main(void)
{
char str[MAXLEN] = "aaabbbcccqwerdd";
char command[MAXLEN] = "sbqwerbkkk";
printf("COMMAND : %s\n", command);
printf("TEXT BEFORE : %s\n", str);
char* pfind = command + 2; // skip initial sb
char* psub = strchr(pfind, 'b'); // find delimiter
*psub = '\0'; // terminate replace string
++psub; // point to substitute substring
size_t flen = strlen(pfind); // calculate length
size_t slen = strlen(psub); // calculate length
char* p = strstr(str, pfind); // find location of replace string
size_t sc = strlen(p); // calculate length
memmove(p + slen, p + flen, sc - flen + 1); // Move trailing part
strncpy(p, psub, slen); // Put in substitute substring
printf("TEXT AFTER : %s\n", str);
return 0;
}
Output:
COMMAND : sbqwerbkkk
TEXT BEFORE : aaabbbcccqwerdd
TEXT AFTER : aaabbbccckkkdd
Disclamer
In order to keep the code example short, the above code blindly trust that the command and the original string form a legal substitution and that there are sufficient memory for the result.
In real code, you need to check that. For instance check that strchr and strstr doesn't return NULL.
I am getting used to writing eBPF code as of now and want to avoid using pointers in my BPF text due to how difficult it is to get a correct output out of it. Using strtok() seems to be out of the question due to all of the example codes requiring pointers. I also want to expand it to CSV files in the future since this is a means of practice for me. I was able to find another user's code here but it gives me an error with the BCC terminal due to the one pointer.
char str[256];
bpf_probe_read_user(&str, sizeof(str), (void *)PT_REGS_RC(ctx));
char token[] = strtok(str, ",");
char input[] ="first second third forth";
char delimiter[] = " ";
char firstWord, *secondWord, *remainder, *context;
int inputLength = strlen(input);
char *inputCopy = (char*) calloc(inputLength + 1, sizeof(char));
strncpy(inputCopy, input, inputLength);
str = strtok_r (inputCopy, delimiter, &context);
secondWord = strtok_r (NULL, delimiter, &context);
remainder = context;
getchar();
free(inputCopy);
Pointers are powerful, and you wont be able to avoid them for very long. The time you invest in learning them is definitively worth it.
Here is an example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/**
Extracts the word with the index "n" in the string "str".
Words are delimited by a blank space or the end of the string.
}*/
char *getWord(char *str, int n)
{
int words = 0;
int length = 0;
int beginIndex = 0;
int endIndex = 0;
char currentchar;
while ((currentchar = str[endIndex++]) != '\0')
{
if (currentchar == ' ')
{
if (n == words)
break;
if (length > 0)
words++;
length = 0;
beginIndex = endIndex;
continue;
}
length++;
}
if (n == words)
{
char *result = malloc(sizeof(char) * length + 1);
if (result == NULL)
{
printf("Error while allocating memory!\n");
exit(1);
}
memcpy(result, str + beginIndex, length);
result[length] = '\0';
return result;
}else
return NULL;
}
You can easily use the function:
int main(int argc, char *argv[])
{
char string[] = "Pointers are cool!";
char *word = getWord(string, 2);
printf("The third word is: '%s'\n", word);
free(word); //Don't forget to de-allocate the memory!
return 0;
}
How can I parse a comma separated char string? I've tried using strtok but I can't get it working.
char str2[] = "$GNRMC,011802.00,A,4104.22420,N,08131.66173,W,0.021,,280218,,,D*78\n";
char *p;
p = strtok(str2, ",");
char *input[8];
int i = 0;
for( i=0;i<8;i++)
{
input[i] = p;
p = strtok(NULL, ",");
}
Ideally I'd like to be able to set a variable to the string. Such as
if (i == 0){
string type = $GNRMC;
}
if (i == 1){
float thisnum = 011802.00
}
etc.
This is being written for a pic so I can't use vectors.
You're upper snippet is working for me, besides two minor issues:
buf should be str2
your array of char pointers is too small to hold all substrings
For the second one, you need to convert your substring to the correct type first.
__
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
#define NUM_SUBSTRINGS 13
char str2[] = "$GNRMC,011802.00,A,4104.22420,N,08131.66173,W,0.021,,280218,,,D*78\n";
char *p;
p = strtok(str2, ",");
char * input[NUM_SUBSTRINGS];
int i = 0;
for(i=0; i<NUM_SUBSTRINGS; i++)
{
char *type = NULL;
float thisnum = 0.0;
if (i == 0){
type = p;
}
if (i == 1){
thisnum = strtof(p, NULL);
}
if(p != NULL)
printf("String %s, type: %s, num: %f\n", p, type, thisnum);
input[i] = p;
p = strtok(NULL, ",");
}
return 0;
}
Through a tcp socket I get a string like this: "SmallTitle fromhost 9595".
Upon reciving it I would like to divide it in to a struct so it's easier to work with.
This is what I have come up with. But there are problems. 1 it is nasty. 2 When printing the struct in the end i recieve garbage output after the string. See output example at the bottom. Should not printf stop at '\0'? Then it might be missing such.
struct recieved {
char what[50];
char from[50];
int value;
};
int main(int argc, char const *argv[]) {
struct recieved leaderRec;
char *word;
char buf[] = "leadervalue host 9569"; //Example recieved input from socket.
word = (char *) malloc(sizeof(char) * 50);
int i = 0;
int count = 1;
do{
if((buf[i] == ' ') || (buf[i+1] == '\0')){
//End of word
//word[strlend(word)+1] = '\0';
//printf("%s\n", word);
if(count == 3){
//The value is here
//get the last number
strncat(word,&buf[i], 1);
leaderRec.value = atoi(word);
//printf("%d\n", value);
}
if(count == 1)
strncpy(leaderRec.what, word, strlen(word));
else if(count == 2)
strncpy(leaderRec.from, word, strlen(word));
free(word);
word = (char *) malloc(sizeof(char) * 50);
count++;
}
else {
//printf("%d\n",i );
//printf("%s\n", &buf[i]);
strncat(word,&buf[i], 1);
}
//printf("%s", &buf[i]);
//printf("%d -", i);
i++;
} while(buf[i] != '\0');
printf("%s\n", leaderRec.what);
printf("%s\n", leaderRec.from);
printf("%d\n", leaderRec.value);
return 0;
}
Output:
leadervalue
host__vdso_get
9569
Any better ways to do this?
How would I avoid the garbage output at the second print in the example output?
But there are problems. 1 it is nasty. 2 When printing the struct in
the end i recieve garbage output after the string.
The "garbage" prints, as have been noted in the comments, are because you are not properly null terminating your strings. For instance, you are not initializing word to an empty string (single null character) before calling strncat.
Any better ways to do this?
Most certainly. I'd suggest using strtok as so:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct received {
char what[50];
char from[50];
int value;
};
int main(void)
{
char buf[] = "leadervalue host 9569";
struct received leaderRec;
/* Initialize leaderRec here */
memset(&leaderRec, 0, sizeof(leaderRec));
char *s = strdup(buf);
char *p = strtok(s, " ");
if (p != NULL) {
strncpy(leaderRec.what, p, sizeof(leaderRec.what));
p = strtok(NULL, " ");
}
if (p != NULL) {
strncpy(leaderRec.from, p, sizeof(leaderRec.from));
p = strtok(NULL, " ");
}
if (p != NULL) {
leaderRec.value = atoi(p);
}
free(s);
printf("%s %s %d\n", leaderRec.what, leaderRec.from, leaderRec.value);
return 0;
}
I am given a file with a string, for example "The United States was founded in *1776*". What I cannot figure out is how to shift letters one space to the left or right and have the letters wrap around. I am able to shift the letters from an a to b but not change its location within the word.
Example of this output would be:
"heT
nitedU
tatesS
asw
oundedf
ni
1776**"
In C, strings are stored as an array of chars in memory. Unlike C++ vectors, you can not insert or remove element within the array, you can only access their value or change their value.
If you declare a C string as follows:
char *myStr = "Fred";
It will be stored in memory as a five character array with the 5th character being the zero value which terminates a C string:
myStr[0] = 'F'
myStr[1] = 'r'
myStr[2] = 'e'
myStr[3] = 'd'
myStr[4] = 0
You need to design a for loop that copies each array element to the one before, while remembering that you need to save the one you are about to overwrite. In this example, it should result in the following copy operations being performed:
len = strlen(myStr);
saveCh = myStr[0];
myStr[0] = myStr[1];
myStr[1] = myStr[2];
myStr[2] = myStr[3];
myStr[3] = saveCh;
So now your job is to create a for loop that does that for any C string of any length.
So to rotate the chars within a C string to the left, you need to copy each char in the array at index i to previous array element i-1. The tricky part is to handle the wrap around properly when i=0 (in this example, you want to copy myStr[0] to myStr[3]. Now do that with a for loop.
You need to also understand that the last character of any C string is the null character (value zero), which terminates a C string. If you modify that element in the array, then your string will break. That is why saveCh is copied to myStr[3] and not to myStr[4].
void rotateStrLeftOneChar(char *myStr) {
// Always check for error and special cases first!
// If myStr is a NULL pointer, do nothing and exit
// If myStr is less than 2 chars, nothing needs to be done too.
if ((myStr != NULL) && (strlen(myStr)>1)) {
int len = strlen(myStr);
char saveCh = myStr[0];
int i = 0;
// Copy each char at index i+1 left to index i in the array
for(i=0; i<len-2; i++)
myStr[i] = myStr[i+1];
// The last character is special and is set to saveCh
myStr[len-1] = saveCh;
}
}
If you just need to output the letters to shift to the left and don't want to change original input then you can do:
#include <stdio.h>
#include <string.h>
void shiftletters(char * input, int i);
int main () {
char input[256];
int shift;
printf("Enter input : ");
scanf("%[^\n]s", input);
printf("Number of shifts : ");
scanf("%d", &shift);
shiftletters(input, shift);
return 0;
}
void shiftletters(char * input, int numshifts)
{
char str[256] = {'\0'};
char * delim = " \t";
char * pch = NULL;
int j, k, len, shifts;
if (input == NULL)
{
printf ("Invalid input\n");
return;
}
strcpy (str, input);
pch = strtok (str, delim);
while (pch != NULL)
{
len = strlen (pch);
if ((numshifts == len) || (len == 1))
{
printf ("%s\n", pch);
pch = strtok (NULL, delim);
continue;
}
if (len < numshifts)
shifts = numshifts % len;
else
shifts = numshifts;
for(j=shifts; j<len; j++)
printf("%c", pch[j]);
for(k=0; k<shifts; k++)
printf("%c", pch[k]);
printf("\n");
pch = strtok (NULL, delim);
}
}
The output of the program:
Enter input : The United States was founded in *1776*
Number of shifts : 1
heT
nitedU
tatesS
asw
oundedf
ni
1776**
like this
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
enum { L = -1, R = 1};
char *rotate(char word[], int dir){
size_t len = strlen(word);
char *temp = malloc(len + 1);
if(!temp){
perror("malloc");
exit(EXIT_FAILURE);
}
strcpy(temp, word);
for(char *src = temp; *src; ++src, ++dir){//or use memmove
word[(dir+len)%len] = *src;
}
free(temp);
return word;
}
int main(int argc, char *argv[]) {
FILE *fp = fopen("data.txt", "r");
if(fp == NULL){
perror("fopen");
exit(EXIT_FAILURE);
}
if(argc < 2){
fprintf(stderr, "Usage %s L|R...\n", argv[0]);
exit(EXIT_FAILURE);
}
char word[64];
while(fscanf(fp, "%63s", word)==1){
for(char *shift = argv[1]; *shift; ++shift){
int dir = *shift == 'L' ? L : R;
rotate(word, dir);
}
printf("%s\n", word);
}
fclose(fp);
}
using memmove version
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
enum { L = -1, R = 1};
char *rotate1(char word[], int dir){
size_t len = strlen(word);
if(len > 2){
char temp;
if(dir == L){
temp = word[0];
memmove(word, word+1, len-1);
word[len-1] = temp;
} else if(dir == R){
temp = word[len-1];
memmove(word+1, word, len-1);
word[0] = temp;
}
}
return word;
}
int main(int argc, char *argv[]) {
FILE *fp = fopen("data.txt", "r");
if(fp == NULL){
perror("fopen");
exit(EXIT_FAILURE);
}
if(argc < 2){
fprintf(stderr, "Usage %s L|R...\n", argv[0]);
exit(EXIT_FAILURE);
}
char word[64];
while(fscanf(fp, "%63s", word)==1){
for(char *shift = argv[1]; *shift; ++shift){
int dir = *shift == 'L' ? L : R;
rotate1(word, dir);
}
printf("%s\n", word);
}
}