C: Take parts from a string without a delimiter (using strstr) - c

I have a string, for example: "Error_*_code_break_*_505_*_7.8"
I need to split the string with a loop by the delimiter "_*_" using the strstr function and input all parts into a new array, let's call it -
char *elements[4] = {"Error", "code_break", "505", "7.8"}
but strstr only gives me a pointer to a char, any help?
Note: the second string "code_break" should still contain "_", or in any other case.

This will get you half-way there. This program prints the split pieces of the string to the standard output; it does not make an array, but maybe you can add that yourself.
#include <stdio.h>
#include <string.h>
#include <malloc.h>
void split(const char * str, const char * delimiter)
{
char * writable_str = strdup(str);
if (writable_str == NULL) { return; }
char * remaining = writable_str;
while (1)
{
char * ending = strstr(remaining, delimiter);
if (ending != NULL) { *ending = 0; }
printf("%s\n", remaining);
if (ending == NULL) { break; }
remaining = ending + strlen(delimiter);
}
free(writable_str);
}
int main(void) {
const char * str = "Error_*_code_break_*_505_*_7.8";
const char * delimiter = "_*_";
split(str, delimiter);
return 0;
}

Here is a function that splits a string into an array. You have to pass the size of the array so that the function won't overfill it. It returns the number of things it put into the array. What it puts into the array is a pointer into the string that was passed. It modifies the string by inserting null characters to end the pieces - just like strtok does.
#include<string.h>
#include<stdio.h>
int split(char *string, char *delimiter, char* array[], int size)
{
int count=0;
char *current=string;
char *next;
while(current && *current!='\0')
{
next=strstr(current,delimiter);
if(!next)break;
*next='\0';
if(count<size) array[count++]=current;
current=next+strlen(delimiter);
}
if(count<size) array[count++]=current;
return count;
}
int main()
{
char string[100]="Error_*_code_break_*_505_*_7.8";
char *array[10];
int size=split(string,"_*_",array,10);
for(int i=0;i<size;i++) puts(array[i]);
return size;
}

Related

How to add/delete element in Flat array in C

I have a structure inside which char array and int value is maintained. I want to treat this char array as a flat array to store the list of strings and the offset will track the starting position where the string is added in the array.
Structure is shown below:
struct A
{
char element[256];
int offset;
}
Also, I want to delete the strings after performing some operation if found.
Please let me know if this feasible. If yes then how?
Yes, append to a.element[a.offset].
To delete, set a.element[0] to the null byte. C strings end at a null byte.
#include <stdio.h>
#include <string.h>
typedef struct
{
char element[256];
int offset;
} A;
void A_append(A* a, const char *str) {
// Concatenate on the end of element.
strcat(&a->element[a->offset], str);
// Increment the offset to the new end.
a->offset += strlen(str);
}
void A_delete(A* a) {
a->element[0] = '\0';
a->offset = 0;
}
int main() {
A a = { .element = "" };
a.offset = 0;
char string1[] = "one";
A_append(&a, string1);
char string2[] = "two";
A_append(&a, string2);
puts(a.element);
A_delete(&a);
puts(a.element);
}
You can also store a pointer to the end of element. It's the same thing, just more direct.
#include <stdio.h>
#include <string.h>
typedef struct
{
char element[256];
char *end;
} A;
void A_append(A* a, const char *str) {
// Concatenate nto the end of element.
strcat(a->end, str);
// Increment the pointer to the new end.
a->end += strlen(str);
}
void A_delete(A* a) {
a->element[0] = '\0';
a->end = a->element;
}
int main() {
A a = { .element = "" };
a.end = a.element;
char string1[] = "one";
A_append(&a, string1);
char string2[] = "two";
A_append(&a, string2);
puts(a.element);
A_delete(&a);
puts(a.element);
}
Finally, if you want to store a list of strings, not concatenate them, consider storing them as pointers.
Since all we have to go on is the question if it's feasible - and the answer is yes. Here's a way showing that it is:
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct A A;
struct A {
char element[256];
int offset;
};
A *A_create() {
A *a = malloc(sizeof *a);
a->offset = 0;
return a;
}
void A_destroy(A *a) {
free(a);
}
// return false if the string doesn't fit
// true if it's successfully added
bool A_add_string(A *a, const char *str) {
size_t len = strlen(str);
if(a->offset + len >= sizeof a->element) return false;
memcpy(a->element + a->offset, str, len + 1);
a->offset += len + 1;
return true;
}
You can now create an A, add \0 terminated strings to it and finally destroy it:
A *a = A_create();
A_add_string(a, "Hello");
A_add_string(a, "world");
A_destroy(a);

Passing multiple strings into a function

i am trying to read several strings into a function for processing. The instructions are to pass each string into the function (not create a 2d array of strings). The parameters must stay the same. Here is what i tried
#include <stdio.h>
#include <math.h>
void convert(char s[]), int counts[]);
int main(void)
{
int i = 0;
int d[2] = {};
char text0[] = "this IS a String 4 you.";
char text1[] = "This sample has less than 987654321 leTTers.";
while(i<2)
{
convert (text[i],d); """ this is wrong but i dont know how to correctly do this
i = i +1;
}
}
void convert(char s[]), int counts[])
{
printf("%s this should print text1 and text2", s );
}
So i have a couple of questions. Is there some sort of special character/operator similiar to the glob module in python that can correctly do the convert (text[i],d) part for me where i try to read in each string. Also the int counts[] purpose is to be filled in with the word and character count in the function. So if i fill in this array in function convertwill main also recognize it since i need to print the word/character count in main without returning the actual counts in convert
You could use temporary string pointer array to pass all strings:
char text1[] = "This sample has less than 987654321 leTTers.";
char const * texts[] = { text0, text1 };
convert (texts, 2, d);
}
void convert(char const * s[], size_t n, int counts[])
{
while(n--) {
*counts++ = strlen(*s);
printf("%s\n", *s++);
}
}
Some notes:
I added char const to function argument type. You should always do that when function does not change the string. If you need to change the string in function, just remove the const.
There is extra argument size_t n to pass array array element count to function. size_t can be found in stddef.h.
i think u lost a "(" in "void convert(char s[]), int counts[]);".
it should be void convert((char s[]), int counts[]);
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void convert(char s[], int counts[]);
int main(void){
int i = 0;
int d[2] = {0};
char text0[] = "this IS a String 4 you.";
char text1[] = "This sample has less than 987654321 leTTers.";
char *text[] = { text0, text1 };
for(i=0; i<2; ++i){
convert (text[i], d);
printf("%d, %d\n", d[0], d[1]);
}
}
void convert(char s[], int counts[]){
printf("%s\n", s );
{
char *temp = strdup(s);
char *word, *delimiter = " \t\n";//Word that are separated by space character.
int count_w=0, max_len=0;
for(word = strtok(temp, delimiter); word ; word = strtok(NULL, delimiter)){
int len = strlen(word);
if(max_len < len)
max_len = len;
++count_w;
}
counts[0] = count_w;
counts[1] = max_len;
free(temp);
}
}

Making an array of tokens and comparing it with another string

I have an *input string from a console. That string might look like: show name year xxx.. and I need an output to look like this:
name: Adi
year: 1994 (for example)..
I have been trying to achieve this by using strtok() function, but I also need to compare every tokon with allowed keyywords(name, year...) if that word is not allowed, than the token needs to be skiped(deleted).. for example in this case it would skip show, and xxx.
Another problem is that I need those tokens in a form of an array in order to work with them and with a structs..
There should be no limit to number of words that could be entered in an input..
I hope you understood what I asked.. so, how to make tokens from a string using strtok or something else and make them be arrays or pointers, and how to compare those tokens with another string ( for example constant: #define NAME "name") and of there are some other inputs to skip(delete) them..
I would really appreciate it if you could help me with this.. Thanks..
I would avoid the array. It provides unnecessary overhead. What you're asking for could be accomplished with something like this:
void parseString(char * string) {
char * name = NULL;
char * year = NULL:
char * ptr = strtok(string, " ");
while (ptr != NULL) {
if (stricmp(ptr, "name") == 0) {
ptr = strtok(ptr, " ");
name = ptr;
/* do whatever with name */
} else if (stricmp(ptr, "year") == 0) {
ptr = strtok(ptr, " ");
/* do whatever with year */
year = ptr;
} /* else if ... */
ptr = strtok(ptr, " ");
}
This gives you a fair amount of flexibility. You check all the terms you need, you don't need to worry about how to allocate the array, and you can access values for settings if necessary.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
char *tolowerstr(char *str){
char *p = str;
while((*p++ = tolower(*p)));
return str;
}
int cmp(const void *a, const void *b){
return strcmp(*(const char **)a, *(const char **)b);
}
bool isBanWord(const char *word){
static const char *table[] =
{ "fuck", "show", "xxx" };//sorted
char **ret, *key;
key = tolowerstr(strdup(word));
ret=bsearch(&key, table, sizeof(table)/sizeof(*table), sizeof(*table), cmp);
free(key);
return !!ret;//ret != NULL ? true : false;
}
//Create and return as a dynamic array of pointer to the copy of the word from a string.
//String passed is destroyed.
char **strToWords(char *str, size_t *size){
const char *delimiters = " .";
size_t count=0;
char **array = malloc(strlen(str)*sizeof(char*));//number of words < string length
if(array){
char *token=strtok(str, delimiters);
for(; token ;token=strtok(NULL, delimiters)){
if(!isBanWord(token))//skip ban word
array[count++] = strdup(token);
}
array[count] = NULL;//End mark
array=realloc(array, (count + 1)*sizeof(*array));//include NULL
}
*size = count;
return array;
}
typedef struct words {
char **words;
size_t n; //number of words
} Words;
void clearWords(Words *w){
size_t i;
for(i=0;i < w->n;++i)
free(w->words[i]);
free(w->words);
w->words = NULL;
w->n = 0;
}
void printWords(Words *w){
size_t i=0;
while(i < w->n){
printf("%s", w->words[i++]);
if(w->words[i])
putchar(' ');
}
putchar('\n');
}
int main(){//DEMO
char sentence[] = "show name year xxx.";//input string. Will be destroyed.
Words w;
w.words = strToWords(sentence, &w.n);
printWords(&w);//name year
clearWords(&w);
return 0;
}

Reversing a C string function crashes?

I'm trying to write a C function to reverse a passed in C style string (ie char *) and return the char pointer of the reversed string. But when I run this in VS2012, nothing is printed in terminal and "main.exe has stopped working" msg shows up.
#include <stdio.h>
#include <string.h>
char * rrev_str(char * str )
{
char *revd_str=""; //I tried char revd_str []="" error: stack around "revd_str" is corrupted
int i,r;
int str_len=strlen(str);
for (i = str_len-1, r=0; i >=0; i--,r++)
{
revd_str[r]= str[i];
}
return revd_str;
}
int main(int argc, char* argv[])
{
char str1 [] ="STEETS";
char str2 [] ="smile everyday!";
//reverse "chars" in a C string and return it
char * rev_string=rrev_str(str1);
}
The problem here is three fold. First you aren't allocating enough space for the reversed string, and secondly you are returning a pointer to a local variable in rrev_str(), and thirdly you're modifying a string literal. You need to allocate space for revd_str on the heap:
char * rrev_str(char * str )
{
int i,r;
int str_len=strlen(str);
char *revd_str=malloc(str_len + 1);
memset(revd_str, 0, str_len + 1);
for (i = str_len-1, r=0; i >=0; i--,r++)
{
revd_str[r]= str[i];
}
return revd_str;
}
Problem: You are accessing invalid memory address.
revd_str is pointing to literal constant string of length 1 and you are accessing it beyond the length which is invalid.
Solution:
Create char array of require length (statically or dynamically).
Reverse the given string.
Pass 2nd param as destination string
syntax: char * rrev_str(char * src, char *dest);
Reverse the given string
char * rrev_str(char * str )
{
int start = 0;
int end = strlen(str) - 1;
char temp;
for (; start < end; start++ ,end--)
{
temp = str[start];
str[start] = str[end];
str[end] = temp;
}
return str;
}
int main(int argc, char* argv[])
{
char string [] ="smile";
//reverse "chars" in a C string and return it
char * rev_string = rrev_str(string);
printf("%s",rev_string);
}
Pass 2nd param as destination string
char * rrev_str(char * src, char *dest)
{
int srcLength = strlen(src);
int destLength = strlen(dest);
int i;
// Invalid destination string
if (srcLength > destLength)
{
return NULL;
}
dest[srcLength] = '\0';
srcLength--;
for (i=0; srcLength >= 0;i++, srcLength--)
{
dest[i] = src[srcLength];
}
return dest;
}
int main(int argc, char* argv[])
{
char string [] ="smile";
char revString[20];
//reverse "chars" in a C string and return it
char * rev_string = rrev_str(string, revString);
printf("%s",rev_string);
}
What! you are doing..
char *revd_str=""; // Creating String Literal which can't be modified because they are read only
char *revd_str[]=""; // Creating Char Array of Size Zero.
So Solution are
Either take reference of your string
char *revd_str = strdup(str);
Or create dynamic char array
char *revd_str = (char*) malloc (strlen(str)+1);
your program will run fine. logic is incorrect for reversing so modify it. A sample solution is given below
char * rrev_str(char * str )
{
char *revd_str=strdup(str);
int i; // no need for extra 'int r'
int str_len=strlen(str);
for (i = 0; i < str_len/2; i++)
{
char temp = revd_str[i];
revd_str[i]= revd_str[str_len - 1 -i];
revd_str[str_len - 1 -i] = temp;
}
return revd_str;
}

Null terminating char pointer

I am completely newbie in C.
I am trying to do simple C function that will split string (char array).
The following code doesn't work properly because I don't know how to terminate char array in the array. There are to char pointers passed in function. One containing original constant char array to be split and other pointer is multidimensional array that will store each split part in separate char array.
Doing the function I encountered obviously lots of hustle, mainly due to my lack of C experience.
I think what I cannot achieve in this function is terminating individual array with '\0'.
Here is the code:
void splitNameCode(char *code, char *output);
void splitNameCode(char *code, char *output){
int OS = 0; //output string number
int loop;
size_t s = 1;
for (loop = 0; code[loop]; loop++){
if (code[loop] == ':'){
output[OS] = '\0'; // I want to terminate each array in the array
OS ++;
}else {
if (!output[OS]) {
strncpy(&output[OS], &code[loop], s);
}else {
strncat(&output[OS], &code[loop], s);
}
}
}
}
int main (int argc, const char * argv[]) {
char output[3][15];
char str[] = "andy:james:john:amy";
splitNameCode(str, *output);
for (int loop = 0; loop<4; loop++) {
printf("%s\n", output[loop]);
}
return 0;
}
Here is a working program for you. Let me know if you need any explanation.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
void splitNameCode(char *code, char **output) {
int i = 0;
char* token = strtok(code, ":");
while (token != NULL) {
output[i++] = token;
token = strtok(NULL, ":");
}
}
int main (int argc, const char *argv[]) {
char* output[4];
char input[] = "andy:james:john:amy";
splitNameCode(input, output);
for (int i = 0; i < 4; i++) {
printf("%s\n", output[i]);
}
return 0;
}
If I understand your intent correctly, you are trying to take a string like andy:james:john:amy and arrive at andy\0james\0john\0amy. If this is the case, then your code can be simplified significantly:
void splitNameCode(char *code, char *output){
int loop;
strncpy(code, output, strlen(code));
for (loop = 0; output[loop]; loop++){
if (output[loop] == ':'){
output[loop] = '\0'; // I want to terminate each array in the array
}
}
}

Resources