I got the following string from the user:
char *abc = "a234bc567d";
but all the numbers can have different lengths than in this example (letters are constants).
How can I get each part of numbers? (again, it can be 234 or 23743 or something else..)
I tried to use strchr and strncpy but I need to allocate memory for this (for strncpy), and I hope there is a better solution.
Thanks.
You can do something like this:
char *abc = "a234bc567d";
char *ptr = abc; // point to start of abc
// While not at the end of the string
while (*ptr != '\0')
{
// If position is the start of a number
if (isdigit(*ptr))
{
// Get value (assuming base 10), store end position of number in ptr
int value = strtol(ptr, &ptr, 10);
printf("Found value %d\n", value);
}
else
{
ptr++; // Increase pointer
}
}
If I understand your question, you are trying to extract the parts of the user input that contain numbers ... and the sequence of numbers can be variable ... but the letters are fixed i.e. a or b or c or d. Correct ... ? The following program may help you. I tried it for strings "a234bc567d", "a23743bc567d" and "a23743bc5672344d". Works ...
int main()
{
char *sUser = "a234bc567d";
//char *sUser = "a23743bc567d";
//char *sUser = "a23743bc5672344d";
int iLen = strlen(sUser);
char *sInput = (char *)malloc((iLen+1) * sizeof(char));
strcpy(sInput, sUser);
char *sSeparator = "abcd";
char *pToken = strtok(sInput, sSeparator);
while(1)
{
if(pToken == NULL)
break;
printf("Token = %s\n", pToken);
pToken = strtok(NULL, sSeparator);
}
return 0;
}
Related
I basically want to test if char *tk[2]; has some value or not stored .
My programs has to do something when tk[0] and tk[1] both have values(a char stored in each of them) , but also do something else when only tk[0] is initialized with something and tk[1] is "empty".
This is my function where i initialize my array of pointers , that uses strtok.
The keywords can be something like "key1 key2" or "key1",so maximum 2 words.
void key(char *keywords[], char *tk[], int k) {
int p = 0;
char *delim = " \n";
int length = strlen(keywords[k]);
char buffer_key[length];
strcpy(buffer_key, keywords[k]);
char *token_key = strtok(buffer_key, delim);
while (token_key != NULL) {
tk[p++] = token_key;
token_key = strtok(NULL, delim);
}
}
and this is the block of code from my main function where i call the key function .
char *tk[2];
key(keywords, tk, k);
Next i want to check if only tk[0] has a char stored (so tk[1] is empty?).
How can i check this ?
You should initialize tk before calling the function. Then you can test if the values are filled in after it returns.
char *tk[2] = {0};
key(keywords, tk, k);
if (tk[0] && !tk[1]) {
// do something
}
So i've seen alot of functions like str_replace(str, substr, newstring) but all of them won't work with numbers so i was wondering if anyone had one that would work with both chars and ints or just int ive been looking everywhere and cant figure out a idea on how to write my own.
my goal exactly is to be able to replace a string with a int value in the string not just string with string
below is the function i use to replace strings and it worked just fine
void strrpc(char *target, const char *needle, const char *replacement)
{
char buffer[1024] = { 0 };
char *insert_point = &buffer[0];
const char *tmp = target;
size_t needle_len = strlen(needle);
size_t repl_len = strlen(replacement);
while (1) {
const char *p = strstr(tmp, needle);
// walked past last occurrence of needle; copy remaining part
if (p == NULL) {
strcpy(insert_point, tmp);
break;
}
// copy part before needle
memcpy(insert_point, tmp, p - tmp);
insert_point += p - tmp;
// copy replacement string
memcpy(insert_point, replacement, repl_len);
insert_point += repl_len;
// adjust pointers, move on
tmp = p + needle_len;
}
// write altered string back to target
strcpy(target, buffer);
}
You can turn an integer into a string by "printing" it to a string:
int id = get_id();
char idstr[20];
sprintf(idstr, "%d", id);
Now you can
char msg[1024] = "Processing item {id} ...";
strrpc(msg, "{id}", idstr);
puts(msg);
But note that the implementation of strrpc you found will work only if the string after replacement is shorter than 1023 character. Also note the the example above could more easily be written as just:
printf("Processing item %d ...\n", get_id());
without the danger of buffer overflow. I don't know what exactly you want to achieve, but perhaps string replacement is not the best solution here. (Just sayin'.)
I'm using the following code to split a char array:
char* Split(char* e, int index) {
index = index -1;
char* v[index +2];
char *p;
int i = 0;
p = strtok(e, ",");
while(p && i < index +2)
{
v[i] = p;
p = strtok(NULL, ",");
i++;
};
// Serial.println(v[0]);
//Serial.println(v[1]);
// Serial.println(v[2]);
return v[index];
};
I'm calling the function like this:
char array[]="1,3,4,55,6,7,66";
Serial.println("array:");
Serial.println(array);
char *out;
out = Split(array,2);
Serial.println("out:");
Serial.println(out);
Serial.println("array:");
Serial.println(array);
out = Split(array,2);
Serial.println("out:");
Serial.println(out);
The first time I call the function, everythin is fine. The result I get is "3" , and that is what I expect.
But with the second call of the function, things goes crazy, and I get just some hieroglyphics.
When I check the variables with the Serial output, I can see that "array" is the second time just "1", and this might be the reason of the curious output of the function.
But I don't understand how the first call of the function can affect the value of "array", because this variable is not touched in the function.
Can anybody help me with clarifying this issue?
The output of the serial interface is lke this:
array:
1,3,4,55,6,7,66
out:
3
array:
1
out:
⸮}⸮a⸮⸮-:⸮⸮⸮m⸮⸮⸮⸮⸮⸮⸮]⸮ʻ⸮T⸮;⸮⸮⸮N}⸮⸮⸮⸮{R⸮U)⸮⸮⸮[G⸮⸮`j⸮⸮⸮⸮⸮v⸮⸮wz⸮⸮s⸮⸮⸮⸮⸮⸮}⸮⸮2⸮⸮vz~⸮⸮⸮⸮O}⸮⸮⸮/⸮⸮nv⸮⸮^j⸮yO⸮7{⸮⸮⸮⸮z⸮Z⸮⸮⸮⸮⸮⸮⸮7[⸮⸮⸮j⸮w⸮⸮⸮⸮⸮⸮⸮w)⸮⸮c⸮⸮}⸮⸮⸮⸮⸮⸮⸮⸮⸮v⸮⸮⸮m/V⸮ys<⸮⸮ٿ⸮⸮⸮׆⸮+>ֻ⸮z6⸮=⸮D⸮⸮⸮⸮~⸮⸮⸮⸮e⸮⸮?⸮=⸮⸮W⸮⸮⸮⸮}⸮e⸮ߣN绮⸮w⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮w⸮⸮⸮⸮?⸮⸮⸮⸮⸮⸮⸮Y⸮⸮f⸮v⸮⸮u⸮p?⸮⸮^h⸮⸮}⸮⸮ݼ⸮^Wo⸮⸮⸮⸮⸮_⸮⸮⸮⸮⸮⸮;s⸮⸮⸮⸮wZ⸮⸮⸮~⸮7⸮⸮⸮r⸮⸮⸮⸮)⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮f⸮⸮O⸮⸮⸮⸮⸮⸮⸮⸮⸮
⸮⸮7⸮⸮a.⸮⸮.kG⸮⸮8⸮⸮⸮⸮⸮⸮⸮⸮U⸮⸮⸮⸮⸮⸮⸮⸮⸮'⸮we⸮⸮⸮M⸮{⸮⸮Lu⸮no⸮⸮⸮>⸮⸮⸮⸮⸮⸮⸮~}⸮⸮⸮⸮⸮⸮⸮⸮y⸮⸮o⸮⸮⸮,'>}⸮⸮⸮+⸮X⸮⸮⸮/⸮⸮ױ⸮⸮⸮⸮̲⸮⸮-_M⸮⸮⸮⸮L~⸮#Φz~⸮⸮⸮⸮?⸮⸮⸮⸮⸮{/⸮_⸮:⸮jmc⸮m]S⸮_3⸮>o⸮⸮ݸv⸮⸮⸮|⸮
⸮⸮{_^⸮⸮o⸮?⸮⸮⸮⸮⸮⸮_⸮⸮⸮⸮{⸮⸮⸮^⸮⸮⸮⸮⸮⸮⸮⸮⸮ퟺ⸮⸮߿⸮⸮p⸮⸮⸮w?=⸮⸮⸮X⸮⸮⸮⸮⸮⸮_⸮oy⸮⸮M⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮w⸮⸮⸮[⸮⸮o⸮⸮⸮⸮7wE~⸮⸮⸮⸮⸮N⸮⸮o⸮x⸮=v/⸮⸮⸮⸮>⸮9⸮⸮ί⸮Y_Q⸮⸮l⸮⸮}'⸮⸮}⸮?⸮⸮ޭ⸮6⸮7⸮{⸮T⸮⸮⸮ ⸮r⸮⸮⸮⸮⸮⸮⸮
ܽ+'⸮⸮⸮⸮G⸮f⸮z⸮Gn⸮⸮n⸮/⸮⸮⸮⸮/⸮⸮⸮⸮Q⸮⸮⸮⸮⸮o⸮;⸮L⸮⸮r⸮⸮⸮⸮n/߿ſ⸮⸮⸮⸮q⸮⸮⸮ݮ⸮⸮⸮⸮⸮⸮+⸮⸮⸮⸮⸮⸮ﷹln?⸮⸮⸮⸮q⸮⸮⸮{⸮⸮⸮⸮⸮⸮⸮q⸮-⸮⸮{(⸮⸮f⸮⸮{⸮v⸮܀⸮oq⸮⸮⸮⸮⸮⸮߽⸮⸮nj⸮⸮⸮os⸮6۟g⸮⸮⸮⸮"⸮⸮7Z7⸮⸮yo⸮ӟ⸮⸮⸮w⸮⸮⸮⸮⸮⸮{⸮⸮⸮Vr⸮⸮]_⸮SS⸮_⸮w⸮⸮⸮wl⸮⸮⸮⸮P⸮⸮z⸮⸮m{⸮⸮⸮ݛs⸮(⸮⸮r⸮⸮˷:⸮%⸮⸮⸮⸮Z⸮⸮⸮m⸮W⸮⸮⸮⸮ם*⸮⸮⸮[>⸮⸮⸮/⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮?⸮⸮⸮⸮|⸮.⸮⸮⸮{⸮⸮⸮ꍥ⸮⸮⸮|⸮⸮⸮⸮⸮⸮⸮⸮⸮7~Ls⸮!⸮⸮⸮⸮⸮{⸮x⸮g⸮⸮|֍om~~⸮⸮⸮{⸮cϠ⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮>;⸮W⸮⸮⸮⸮⸮⸮⸮⸮q⸮⸮[:⸮'⸮#⸮o⸮⸮_⸮uϾ⸮⸮⸮⸮[⸮⸮^⸮⸮⸮n⸮}⸮⸮⸮⸮⸮>/⸮_⸮⸮-⸮⸮⸮⸮s⸮⸮⸮}⸮⸮⸮⸮/⸮[w⸮⸮r⸮⸮_⸮⸮⸮⸮,⸮⸮ݯ⸮⸮⸮7ÿ⸮:⸮⸮⸮⸮Ί⸮⸮⸮⸮⸮t[|⸮⸮w⸮F⸮⸮⸮
Has anybody a better idea?
The solution depend on your data, if your data is always like a string with list of integers separated with ,, then it will probably better to split it into an int array, you can then write a generic split() function.
#define NUMBER_OF_ELEMENT 7
int splitted[NUMBER_OF_ELEMENT];
const char* delimiter = ",";
void split(const char *str, const char *delimiter) {
char temp[strlen(str)+1] = {0};
memcpy(temp, str, strlen(str));
int i=0;
char *p = strtok(temp, delimiter);
while(p != NULL) {
splitted[i++] = atoi(p);
p = strtok(NULL, delimiter);
}
}
int setup() {
char array[]="1,3,4,55,6,7,66";
Serial.begin(115200);
split(array, delimiter);
// get every splitted element as an int
for (int i=0; i<NUMBER_OF_ELEMENT, i++) {
Serial.print("Out:");
Serial.println(splitted[i]);
}
//if you really want to have string as result
Serial.println(String(splitted[3]));
}
OK I got it by making the array independent from change by strtok:
void setup(){
Serial.begin(115200);
char array[]="1,3,4,55,6,7,66";
char *out;
char array2[8];
strcpy(array2,array);
Serial.println("array2:");
Serial.println(array2);
out = Split(array2,2);
Serial.println("out:");
Serial.println(out);
Serial.println("array3:");
char array3[8];
strcpy(array3,array);
Serial.println(array3);
out = Split(array3,2);
Serial.println("out:");
Serial.println(out);
}
Not that elegant, but it works!!
Has anybody a better idea?
Thanks,great!
Yes my data is always int. So your function is perfect for me.
But for the sake of a clear structure, I would prefer to work with a return value, instead of changing the global variable "splitted".
Is that a good practice? Or do you prefer your variant for saving RAM?
Here my final solution for this task. The function just returns a single value, according to the given index:
int splitStrToInt(char *str, int index) {
//******************
//This function splits a string that is separated by commas and converts the values to int,
//according to the given index
//caution!! The string may only consist of numerical values !!
//Example: "1,3,4,55,6,7,66"
//******************
index--;
char e[strlen(str) + 1] = { 0 };
memcpy(e, str, strlen(str));
int v[index + 2];
char *p;
int i = 0;
p = strtok(e, ",");
while (p && i < index + 2) {
v[i] = atoi(p);
p = strtok(NULL, ",");
i++;
}
;
return v[index];
}
Right now, I'm attempting to familiarize myself with C by writing a function which, given a string, will replace all instances of a target substring with a new substring. However, I've run into a problem with a reallocation of a char* array. To my eyes, it seems as though I'm able to successfully reallocate the array string to a desired new size at the end of the main loop, then perform a strcpy to fill it with an updated string. However, it fails for the following scenario:
Original input for string: "use the restroom. Then I need"
Target to replace: "the" (case insensitive)
Desired replacement value: "th'"
At the end of the loop, the line printf("result: %s\n ",string); prints out the correct phrase "use th' restroom. Then I need". However, string seems to then reset itself: the call to strcasestr in the while() statement is successful, the line at the beginning of the loop printf("string: %s \n",string); prints the original input string, and the loop continues indefinitely.
Any ideas would be much appreciated (and I apologize in advance for my flailing debug printf statements). Thanks!
The code for the function is as follows:
int replaceSubstring(char *string, int strLen, char*oldSubstring,
int oldSublen, char*newSubstring, int newSublen )
{
printf("Starting replace\n");
char* strLoc;
while((strLoc = strcasestr(string, oldSubstring)) != NULL )
{
printf("string: %s \n",string);
printf("%d",newSublen);
char *newBuf = (char *) malloc((size_t)(strLen +
(newSublen - oldSublen)));
printf("got newbuf\n");
int stringIndex = 0;
int newBufIndex = 0;
char c;
while(true)
{
if(stringIndex > 500)
break;
if(&string[stringIndex] == strLoc)
{
int j;
for(j=0; j < newSublen; j++)
{
printf("new index: %d %c --> %c\n",
j+newBufIndex, newBuf[newBufIndex+j], newSubstring[j]);
newBuf[newBufIndex+j] = newSubstring[j];
}
stringIndex += oldSublen;
newBufIndex += newSublen;
}
else
{
printf("old index: %d %c --> %c\n", stringIndex,
newBuf[newBufIndex], string[stringIndex]);
newBuf[newBufIndex] = string[stringIndex];
if(string[stringIndex] == '\0')
break;
newBufIndex++;
stringIndex++;
}
}
int length = (size_t)(strLen + (newSublen - oldSublen));
string = (char*)realloc(string,
(size_t)(strLen + (newSublen - oldSublen)));
strcpy(string, newBuf);
printf("result: %s\n ",string);
free(newBuf);
}
printf("end result: %s ",string);
}
At first the task should be clarified regarding desired behavior and interface.
The topic "Char array..." is not clear.
You provide strLen, oldSublen newSublen, so it looks that you indeed want to work just with bulk memory buffers with given length.
However, you use strcasestr, strcpy and string[stringIndex] == '\0' and also mention printf("result: %s\n ",string);.
So I assume that you want to work with "null terminated strings" that can be passed by the caller as string literals: "abc".
It is not needed to pass all those lengths to the function.
It looks that you are trying to implement recursive string replacement. After each replacement you start from the beginning.
Let's consider more complicated sets of parameters, for example, replace aba by ab in abaaba.
Case 1: single pass through input stream
Each of both old substrings can be replaced: "abaaba" => "abab"
That is how the standard sed string replacement works:
> echo "abaaba" | sed 's/aba/ab/g'
abab
Case 2: recursive replacement taking into account possible overlapping
The first replacement: "abaaba" => "ababa"
The second replacement in already replaced result: "ababa" => "abba"
Note that this case is not safe, for example replace "loop" by "loop loop". It is an infinite loop.
Suppose we want to implement a function that takes null terminated strings and the replacement is done in one pass as with sed.
In general the replacement cannot be done in place of input string (in the same memory).
Note that realloc may allocate new memory block with new address, so you should return that address to the caller.
For implementation simplicity it is possible to calculate required space for result before memory allocation (Case 1 implementation). So reallocation is not needed:
#define _GNU_SOURCE
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
char* replaceSubstring(const char* string, const char* oldSubstring,
const char* newSubstring)
{
size_t strLen = strlen(string);
size_t oldSublen = strlen(oldSubstring);
size_t newSublen = strlen(newSubstring);
const char* strLoc = string;
size_t replacements = 0;
/* count number of replacements */
while ((strLoc = strcasestr(strLoc, oldSubstring)))
{
strLoc += oldSublen;
++replacements;
}
/* result size: initial size + replacement diff + sizeof('\0') */
size_t result_size = strLen + (newSublen - oldSublen) * replacements + 1;
char* result = malloc(result_size);
if (!result)
return NULL;
char* resCurrent = result;
const char* strCurrent = string;
strLoc = string;
while ((strLoc = strcasestr(strLoc, oldSubstring)))
{
memcpy(resCurrent, strCurrent, strLoc - strCurrent);
resCurrent += strLoc - strCurrent;
memcpy(resCurrent, newSubstring, newSublen);
resCurrent += newSublen;
strLoc += oldSublen;
strCurrent = strLoc;
}
strcpy(resCurrent, strCurrent);
return result;
}
int main()
{
char* res;
res = replaceSubstring("use the restroom. Then I need", "the", "th");
printf("%s\n", res);
free(res);
res = replaceSubstring("abaaba", "aba", "ab");
printf("%s\n", res);
free(res);
return 0;
}
How do we return a string from a function?
I'm just beginning to learn to use the string functions and malloc, basically, i'm trying to get:
ef = 11101111
as an output.
Here's what i've tried.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
const int MAXWORD = 2;
char hexToBinary(char hex[MAXWORD]);
int main()
{
char hex[MAXWORD] = {'e','f'};
printf("%s = %s\n", hex, hexToBinary(hex));
return 0;
}
char hexToBinary(char hex[MAXWORD])
{
char *hexToBn = malloc( (MAXWORD-1) * sizeof(char) );
char *convertedString = malloc( (MAXWORD-1) * sizeof(char) );
for(int i=0 ; i<MAXWORD ; ++i)
{
if(hex[i] == 'e' || hex[i] == 'E')
{
strcpy(hexToBn, "1110");
}
if(hex[i] == 'f' || hex[i] == 'F')
{
strcpy(hexToBn, "1111");
}
strcat(convertedString, hexToBn);
}
return convertedString;
}
If you would like to make a function that returns a C string, declare it returning char*:
char *hexToBinary(char hex[MAXWORD]) {
...
}
This is not ideal, because it creates a possibility of a memory leak. In fact, your code would leak a string, because you never free what's allocated in malloc.
You should either fix the leak by capturing the return value and calling free once you are done with it, or use the buffer+length API pattern:
char *bin = hexToBinary(hex);
printf("%s = %s\n", hex, bin);
free(bin);
An alternative API would look like this:
void hexToBinary(char hex[], char bin[], int len) {
... // Users pass the output buffer bin and its length len
}
Couple ways to do so:
1: Allocate string on the heap and pass it to the caller. The caller ensures the string is delete using free.
char * get_str()
{
char * str = malloc(string_length + 1);
// Do something
return str;
}
2: pass the string to the function
void update_string(char * input, int length)
{
// modify string
}
Declare the return type as char*. Then use it like you would.
Note: you may have to do other things to your code. I just said the first thing I saw at a glance. Also, you need to make sure that your memory is deallocated with free when you are done with it.