How to convert comma separated char* to uint32_t[] array in C - c

I want to convert a comma separated char* to an uint32_array[] in C. Is there an easy method/routine to do that?
I already spend a lot of time on SO and found many solutions on C++, but not an C like that :
Parsing a comma-delimited std::string
But I think it is not a good solution to cast from char* to string to string stream to vector and work with the vector.
char input[] = "1 , 2 , 34, 12, 46, 100";
to
uint32_t output[] = { 1 , 2 , 34, 12, 46, 100 };
I would appreciate any kind of help. Thanks a lot.

Here's a recursive algorithm that only makes a single pass. It allocates at the deepest level and fills in on the way out:
int *cvt(char *input, int *level)
{
char *cp = strtok(input, ", ");
if (cp == NULL) {
/* No more separators */
return (int *) malloc(sizeof(int) * *level);
}
int my_index = -1;
int n;
if (sscanf(cp, "%d", &n) == 1) {
my_index = *level;
*level += 1;
} else {
printf("Invalid integer token '%s'\n", cp);
}
int *array = cvt(NULL, level);
if (my_index >= 0) {
array[my_index] = n;
}
return array;
}
Call with:
int main(int ac, char **av)
{
char input[] = "1, 2, bogus, 4, 8, 22, 33, 55";
int n_array = 0;
int *array = cvt(input, &n_array);
int i;
printf("Got %d members:\n", n_array);
for (i = 0; i < n_array; ++i)
printf("%d ", array[i]);
printf("\n");
return 0;
}

One method (of many):
int converted = 0 ;
char* tok = input ;
int i = 0 ;
do
{
converted = sscanf( tok, "%d", &output[i] ) ;
tok = strchr( tok, ',' ) + 1 ;
i++ ;
} while( tok != NULL && converted != 0 ) ;
You could use strtok() instead of sscanf() and strchr(), but that modifies input which may be undesirable.
If the input is a stream rather than a string, then it is simpler:
int converted = 0 ;
int i = 0 ;
do
{
converted = fscanf( fd, "%d,", &output[i] ) ;
i++ ;
} while( !feof( fd ) && converted != 0 ) ;
I have not included any means to prevent output[i] from exceeding the bounds - you may need to consider that too.

Here is one way to do it:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
int* values;
int count;
}
output_t;
output_t Read(char input[])
{
int* values = NULL;
int count = 0;
char* pch = strtok(input,", ");
while (pch != NULL)
{
values = realloc(values,(count+1)*sizeof(*values));
values[count++] = atoi(pch);
pch = strtok(NULL,", ");
}
return (output_t){values,count};
}
And here is a usage example:
void Example()
{
char input[] = "1 , 2 , 34, 12, 46, 100";
output_t output = Read(input);
for (int i=0; i<output.count; i++)
printf("%d\n",output.values[i]);
free(output.values);
}

I'll throw my hat into the ring and do a single pass of the data. I estimate the required array size to be the worst case where every data is of the form "n," so two bytes per number, and resize it afterwards.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef unsigned int uint32_t;
int main (void) {
char input[] = "1 , 2 , 34, 12, 46, 100";
uint32_t *output, *temp;
char *tok;
int elements = 0;
int len = 1 + strlen(input) / 2; // estimate max num of elements
output = malloc(len * sizeof(*output));
if (output == NULL)
exit(-1); // memory alloc error
tok = strtok(input, ", "); // parse the string
while (tok != NULL) {
if (elements >= len)
exit(-2); // error in length assumption
if (1 != sscanf(tok, "%u", output + elements))
exit(-3); // error in string format
elements++;
tok = strtok(NULL, ", ");
}
temp = realloc(output, elements * sizeof(*output)); // resize the array
if (temp == NULL)
exit(-4); // error in reallocating memory
output = temp;
for (len=0; len<elements; len++)
printf("%u ", output[len]);
printf("\n");
free(output);
return 0;
}
Program output:
1 2 34 12 46 100

Read through the string once to figure out how to size your array:
uint32_t n = 1;
for (uint32_t idx = 0; idx < strlen(input); idx++) {
if (input[idx] == ',') {
n++;
}
}
There's a different way to do this that doesn't require reading through the string, but it requires resizing the destination array as new elements come in, which makes the code more complex. It's easy enough to read through the string once for small strings.
Make your destination array:
uint32_t* output = NULL;
output = malloc(sizeof(*output) * n);
if (!output) {
fprintf(stderr, "Error: Could not allocate space for output array!\n");
exit(EXIT_FAILURE);
}
Populate your array. One way to do this without clobbering the string is to keep a couple pointers to the start and end of a substring that contains the desired numeric element in the comma-separated string, and just loop over all the characters in the string:
#define MAX_LEN 13
char* start = &input[0];
char* end = &input[0];
char entry[MAX_LEN];
uint32_t entry_idx = 0;
int finished = 0; // false
do {
end = strchr(start, ',');
if (!end) {
end = input + strlen(input);
finished = 1;
}
memcpy(entry, start, end - start);
entry[end - start] = '\0';
sscanf(entry, "%u", &output[entry_idx++]);
start = end + 1;
} while (!finished);
MAX_LEN is 13 because it is unlikely that a uint32_t will be longer than 13 digits. You can make this longer to future-proof this for computers made in the year 2100.
Be sure to free the array when you're done with it:
free(output);
output = NULL;

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
int getsize(char* str, char* delimiters) //give the size of the final uint32_t array[]
{
int count = 0;
char* st = strdup(str), *t = strtok(st, delimiters);
while(t)
{
count++;
t = strtok(NULL, delimiters);
}
free(st);
return count;
}
uint32_t* Char_to_Array(char *data, char* delimiters, int *siz) //siz is a pointer to get the size of the array
{
char* st = strdup(data), *t = NULL; //dup string, strtok mage change on the passed string
*siz = getsize(data, delimiters);
uint32_t* buf=(uint32_t *)malloc((*siz)*4);
t = strtok(st, delimiters); //split string by " "
int i = 0;
while(t)
{
buf[i] = atoi(t);
t = strtok(NULL, delimiters);
i++;
}
free(st);
return buf;
}
here a test with a main function
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
int main()
{
int getsize(char* str, char* delimiters), siz = 0, i = 0;
uint32_t* Char_to_Array(char *data, char* delimiters, int *x);
uint32_t* t = Char_to_Array("123, 156, 4658,7878", " ,", &siz);
while(i<siz)
{
printf("array[%d] = %d\n", i, t[i]);
i++;
}
free(t);
return 0;
}

2 pass approach:
1) Count the number of commas and allocate an array.
2) Parse the string - look for errors.
[Late to the uint32 comma party]
#include <errno.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <inttypes.h>
typedef struct {
uint32_t *u32;
size_t count;
bool error;
} CSV_32_T;
CSV_32_T CSV_to_int32_list(const char *csv) {
CSV_32_T list = { NULL, 1, false };
// 1st pass: Quickly go through list counting commas
const char *p = csv;
for (p = csv; *p; p++) {
if (*p == ',') {
list.count++;
}
}
size_t i = 0;
list.u32 = malloc(list.count * sizeof *list.u32);
if (list.u32) {
// 2nd pass: scan
p = csv;
for (i = 0; i < list.count; i++) {
if (i > 0 && *p++ != ',') {
break;
}
int n = 0;
if (1 != sscanf(p, "%" SCNu32 " %n", &list.u32[i], &n)) {
break;
}
p += n;
}
}
if (i != list.count || *p) {
free(list.u32);
return (CSV_32_T ) { NULL, 0, true } ;
}
return list;
}
void testCSV(const char *csv) {
CSV_32_T y = CSV_to_int32_list(csv);
printf("%d %zu \"%s\"\n", y.error, y.count, csv);
}
int main(void) {
testCSV("1 , 2 , 34, 12, 46, 100");
testCSV("1 2 , 34, 12, 46, 100");
return 0;
}

Related

Not getting output from string array function in c

I was making a split function in C to use its return value in some programs. But when I checked its value using printf, I discovered that there are some errors but I was unable to fix them myself. I fixed most of the errors I could.
The code I wrote is:
#include <stdio.h>
#include <string.h>
char **split(char *token, char *delimiter, int *a[], int *size_of_a) {
int i = 0;
char **final_result;
char *str = strtok(token, delimiter);
while (str != NULL) {
*a[i] = strlen(str); //maybe one of the errors but I don't know how to fix it
//even after removing a[i] by backslash and changing it in loop and main, there is still no output received in main
getch();
for (int j = 0; j < *a[i]; j++) {
final_result[i][j] = str[j];
}
str = strtok(NULL, delimiter);
i++;
}
*size_of_a = i;
return final_result;
}
int main() {
char *parameter_1;
char *parameter_2;
int *size_1;
int size_2;
printf("Enter the token: ");
scanf("%s", &parameter_1);
printf("\nEnter the delimiter: ");
scanf("%s", &parameter_2);
char **result_2 = split(parameter_1, parameter_2, &size_1, &size_2);
printf("\nThe result is:");
for (int x = 0; x < size_2; x++) {
printf('\n');
for (int y = 0; y < size_1[x]; y++) {
printf("%c", result_2[x][y]);
}
}
getch();
return 0;
}
How can I fix the output error?
There are multiple problems in the code:
You do not allocate space for the array of pointers: final_result is uninitialized, storing anything via dereferencing it has undefined behavior, most likely a segmentation fault.
You should use strcpn() and strspn() to compute the number of tokens, allocate the array with or without an extra slot for a NULL terminator and perform a second phase splitting the tokens and storing the pointers to the array. You might want to store copies of the tokens to avoid modifying the original string that may be constant or go out of scope.
printf('\n'); is invalid: you must pass a string, not a character constant.
scanf("%s", &parameter_1); also has undefined behavior: you pass the address of a pointer instead of a pointer to an array of char.
Here is a modified version:
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _MSC_VER
// define POSIX function strndup if not available
char *strndup(const char *s, size_t n) {
size_t len;
for (len = 0; len < n && s[len]; len++)
continue;
char *ptr = malloc(len + 1);
if (ptr) {
memcpy(ptr, s, len);
ptr[len] = '\0';
}
return ptr;
}
#endif
char **split(const char *str, const char *delimiters, int **a, int *size_of_a) {
int i, count, len;
char **final_result;
const char *p;
// phase 1: count the number of tokens
p = str + strspn(str, delimiters);
for (count = 0; *p; count++) {
p += strcspn(p, delimiters);
p += strspn(p, delimiters);
}
// phase 2: allocate the arrays
final_result = calloc(sizeof(*final_result), count + 1);
if (a) {
*a = calloc(sizeof(**a), count);
}
if (size_of_a) {
*size_of_a = count;
}
// phase 3: copy the tokens
p = str;
for (i = 0; i < count; i++) {
p += strspn(p, delimiters); // skip the delimiters
len = strcspn(p, delimiters); // count the token length
if (a) {
(*a)[i] = len;
}
final_result[i] = strndup(p, len); // duplicate the token
p += len;
}
final_result[count] = 0;
return final_result;
}
// read and discard the rest of the user input line
int flush_input(void) {
int c;
while ((c = getchar()) != EOF && c != '\n')
continue;
return c;
}
int main() {
char buf[256];
char delimiters[20];
printf("Enter the string: ");
if (scanf("%255[^\n]", buf) != 1)
return 1;
flush_input();
printf("\nEnter the delimiters: ");
if (scanf("%19[^\n]", delimiters) != 1)
return 1;
flush_input();
int *sizes;
int count;
char **array = split(buf, delimiters, &sizes, &count);
printf("\nThe result is:\n");
for (int x = 0; x < count; x++) {
for (int y = 0; y < sizes[x]; y++) {
putchar(array[x][y]);
}
printf("\n");
}
getchar();
return 0;
}

Split a file of text at delimiters and separate integers and text in c

I am reading text from an input file in. I have to separate text from scores ie
John Doe 100 95 67 85
jane doe 67 78 99
and then average the numbers. I can separate by the spaces using strtok but how can i tell when i have an integer? i need to split the reading of names and of integers into 2 functions. My code to read it works but i need to stop at the end of each name. I attempted to use numbers converted to strings and using strcmp however it did not work.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void read_reverse_write(FILE * ptr_file, FILE * op);
void write_and_avarage(int * fp, char * op);
//int checker(char *token);
int main(int argc, char** argv) {
FILE *fp;
FILE *op;
//opens quiz and checks and checks to make sure it did
fp = fopen("quiz.txt", "r");
if (fp == NULL) {
printf("Error opening file");
return (-1);
}
//opens op and checks that it did
op = fopen("output.txt", "w");
if (op == NULL) {
printf("Error opening file");
return (-1);
}
// runs read reverse write
read_reverse_write(fp, op);
fclose(fp);
fclose(op);
return (EXIT_SUCCESS);
}
void read_reverse_write(FILE * ptr_file, FILE * op) {
char buf[1000];
char *token;
const char delim[2] = " ";
fgets(buf, 1000, ptr_file);
token = strtok(buf, delim);
while (token != 100) {
fprintf(op, "%s ", token);
token = strtok(NULL, delim);
}
}
/*void write_and_avarage(int * fp, char * op) {
}
int checker(char *token) {
char *arr[102];
char ph[4];
for (int p = 0; p < 100; p++) {
if (p < 10) {
snprintf(ph, 1, "%d", p);
arr[p] = ph;
} else if (p < 99) {
snprintf(ph, 2, "%d", p);
arr[p] = ph;
} else if (p = 100) {
snprintf(ph, 3, "%d", p);
arr[p] = ph;
}
}
for (int z = 0; z < 100; z++) {
if (strcmp(token, arr[z]) == 1) {
return 1;
} else {
z++;
}
return 0;
}
}
*/
You can use the following code to check the whether the string is a number or not.
#include <stdio.h>
#include <string.h>
#define MAX_NUM 9
#define MIN_NUM 0
#define ZERO 0
#define MAX_SIZE 1024
int checkDigit(int num, int len)
{
int divisor = 1, checkVal = 0;
if(len <= 2)
divisor = 10;
else if(len > 2)
{
len = len - 1;
while(len != ZERO)
{
divisor = divisor * 10;
len = len - 1;
}
}
checkVal = num/divisor;
if(checkVal > MIN_NUM && checkVal <= MAX_NUM)
return 1;
else
return 0;
}
void main()
{
char array[MAX_SIZE] = "JOHN DOE 120 DOE HELLO 2323 90909";
char *split_token = NULL;
int status = 2, len = 0, sum = 0, total_digits = 0;
float average = 0;
split_token = strtok(array, " ");
while( split_token != NULL )
{
len = strlen(split_token);
status = checkDigit(atoi(split_token), len);
if (1 == status)
{
sum = sum + atoi(split_token);
total_digits = total_digits + 1;
}
split_token = strtok(NULL, " ");
}
average = (float)sum/total_digits;
printf("Average is : %f\n", average);
}
This code will check whether your string is a number or not and finally calculate the average of all the numbers in the given string.
If you need to read from a file, multiple sets of inputs, use fscanf() and use the complete code logic repeatedly for each line of input.
Hope it helps! Do ask if you need the complete code or any clarification for the code.

Incorrect behavior of a pointer in function in C

I have a problem with the following program.
The main function calls the function returnArrayOfWords(arrS1, &ptrArray1) twice. On the first call, the array is parsed perfectly, and afterward the pointer always points to the first word. On the other hand, after the second call, the pointer of the first array points to the second word, the third word, or sometimes the first word, but it should always point to the first word -- nowhere else.
Why does the function misbehave when called for the second time?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void returnArrayOfWords (char *str4Parsing, char *arrayParsed[])
{
char seps[] = " ,\t\n"; // separators
char *token1 = NULL;
char *next_token1 = NULL;
int i = 0;
// Establish string and get the first token:
token1 = strtok_s( str4Parsing, seps, &next_token1);
// While there are tokens in "str4Parsing"
while (token1 != NULL)
{
// Get next token:
if (token1 != NULL)
{
arrayParsed[i] = token1;
printf( " %s\n", token1 );
token1 = strtok_s( NULL, seps, &next_token1);
i++;
}
}
}
//int main1 ()
int main ()
{
int i, j, n = 80; /*max number of words in string*/
char arrS1[80], arrS2[80];
const char *w1, *w2; /*pointers*/
char *ptrArray1, *ptrArray2;
int currLength1 = 0, currLength2 = 0 ;
int sizeArr1 = 0, sizeArr2 = 0;
int maxLength = 0;
char wordMaxLength ;
printf("Type your first string: ");
fgets(arrS1, 80, stdin);
returnArrayOfWords(arrS1, &ptrArray1);
sizeArr1 = sizeof(ptrArray1) / sizeof(ptrArray1[0]);
printf("Type your second string: ");
fgets(arrS2, 80, stdin);
returnArrayOfWords(arrS2, &ptrArray2);
sizeArr2 = sizeof(ptrArray2) / sizeof(ptrArray2[0]);
for (i = 0; i < sizeArr1; i++)
{
// to find the largest word in the array
w1 = &ptrArray1[i];
currLength1 = strlen(w1);
for (j = 0; j < sizeArr2; j++)
{
w2 = &ptrArray2[j];
currLength2 = strlen(w2);
if (strcoll(w1, w2) == 0)
// compares the strings
{
if (currLength2 >= maxLength)
// in the 0th element -> the length of the longest word
{
maxLength = currLength2;
wordMaxLength = ptrArray2[j];
}
}
}
}
printf("The largest word is: %s", wordMaxLength);
return 0;
}
EDIT:
Here's the latest version of the code, everything here works fine, managed to fix it myself. I'm just posting it in case somebody needs it as a solution:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <ctype.h>
#define n 80 /*max number of words in string*/
/* Arrays and pointers */
int returnArrayOfWords (char *str4Parsing, char *arrayParsed[])
{
// returns the length of array
int elArr = 0, na = 0;
char *delim = " .,;-\t\n"; /* word delimiters */
char *next_token1 = NULL;
char *ap = str4Parsing; /* pointer to str4Parsing */
for (ap = strtok_s (str4Parsing, delim, &next_token1); ap; ap = strtok_s( NULL, delim, &next_token1))
{
arrayParsed[na++] = ap;
elArr++;
}
return elArr;
}
void printArr(char *arr[])
{
int i;
for ( i = 0; i < n; i++)
{
printf("Element %d is %s \n", i, arr[i]);
}
}
void findLargestWord(char *ptrArray1[], int sizeArr1, char *ptrArray2[], int sizeArr2)
{
size_t maxLength = 0;
char *wordMaxLength = NULL ;
int i = 0, j = 0;
char *w1 = NULL, *w2 = NULL; /*pointers*/
size_t currLength1 = 0, currLength2 = 0 ;
for (i = 0; i < sizeArr1; i++)
{
// to find the largest word in the array
w1 = (ptrArray1[i]); // value of address (ptrArray1 + i)
currLength1 = strlen(w1);
//printf("The word from the first string is: %s and its length is : %d \n", w1, currLength1); // check point
for (j = 0; j < sizeArr2; j++)
{
w2 = (ptrArray2[j]); // value of address (ptrArray2 + j)
currLength2 = strlen(w2);
//printf("The word from the second string is : %s and its length is : %d \n", w2, currLength2); // check point
if (strcoll(w1, w2) == 0 && currLength1 == currLength2)
// compares the strings
{
if (currLength2 >= maxLength)
// in the variable maxLength -> the length of the longest word
{
maxLength = currLength2;
wordMaxLength = w2;
//printf("The largest word for now is : %s and its length is : %d \n", wordMaxLength, maxLength); // check point
}
}
}
}
printf("The largest word is: %s \n", wordMaxLength);
printf("Its length is: %d \n", maxLength);
}
void typeArray (char *arrS1)
{
int err = 0;
if (!fgets (arrS1, n, stdin)) { /* validate 'arrS1' */
fprintf (stderr, "Error: invalid input for string.\n");
err = 1;
}
while (err == 1)
{
if (!fgets (arrS1, n, stdin)) { /* validate 'arrS1' */
fprintf (stderr, "Error: invalid input for string.\n");
err = 1;
}
}
}
int main(void)
{
char arrS1[n], arrS2[n];
char *ptrArray1[n] = {NULL}, *ptrArray2[n] = {NULL};
int sizeArr1 = 0, sizeArr2 = 0;
printf("Type your first string: ");
typeArray (arrS1);
sizeArr1 = returnArrayOfWords (arrS1, ptrArray1); // sizeArr1 = number of elements in array 1
printf("Type your second string: ");
typeArray (arrS2);
sizeArr2 = returnArrayOfWords (arrS2, ptrArray2); // sizeArr2 = number of elements in array 2
findLargestWord(ptrArray1, sizeArr1, ptrArray2, sizeArr2);
return 0;
}
There are numerous errors in the program although it compiled without any warnings. Chiefly the pointer types for your array, and the memory allocated. Secondly the function does not know how many words is allowed, and does not return how many were read - your method did not work at all (as in comments). Thirdly the string comparisons: you did not state the goals clearly, but in comment you want the "biggest string". strcoll does not do that - it's a lexical comparison, so I changed that section to find the longest string for the two sentences you enter. See comments, I made a large number of changes.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int returnArrayOfWords (char *str4Parsing, char *arrayParsed[], int maxtokens) // added max
{
char seps[] = " ,\t\n"; // separators
char *token1 = NULL;
char *next_token1 = NULL;
int i = 0;
// Establish string and get the first token:
token1 = strtok_s( str4Parsing, seps, &next_token1);
// While there are tokens in "str4Parsing"
while (token1 != NULL)
{
if(i >= maxtokens)
return i; // ignore the rest
arrayParsed[i] = token1;
printf( " %s\n", token1 );
token1 = strtok_s( NULL, seps, &next_token1);
i++;
}
return i;
}
int main (void) // correct signature
{
int i, j, n = 80; /*max number of words in string*/
char arrS1[80], arrS2[80];
//const char *w1, *w2; /*pointers*/ // deleted
char **ptrArray1, **ptrArray2; // changed type
int currLength1 = 0, currLength2 = 0 ;
int sizeArr1 = 0, sizeArr2 = 0;
int maxLength = 0;
char *wordMaxLength; // changed to pointer
ptrArray1 = malloc(n * sizeof (char*)); // allocate mem for pointer array
if (ptrArray1 == NULL)
return 1;
ptrArray2 = malloc(n * sizeof (char*)); // allocate mem for pointer array
if (ptrArray2 == NULL)
return 1;
printf("Type your first string: ");
fgets(arrS1, 80, stdin);
sizeArr1 = returnArrayOfWords(arrS1, ptrArray1, n); // indirection error, added max words, get actual num
printf("Type your second string: ");
fgets(arrS2, 80, stdin);
sizeArr2 = returnArrayOfWords(arrS2, ptrArray2, n); // indirection error, added max words, get actual num
for (i = 0; i < sizeArr1; i++) // this section rewritten
{
// to find the largest word in the array
currLength1 = strlen(ptrArray1[i]);
if(currLength1 > maxLength)
{
maxLength = currLength1;
wordMaxLength = ptrArray1[i]; // changed definition to pointer
}
}
for (j = 0; j < sizeArr2; j++)
{
// to find the largest word in the array
currLength2 = strlen(ptrArray2[j]);
if(currLength2 > maxLength)
{
maxLength = currLength2;
wordMaxLength = ptrArray2[j]; // changed definition to pointer
}
}
printf("The largest word is: %s", wordMaxLength);
free(ptrArray1); // added
free(ptrArray2);
return 0;
}
Program session:
Type your first string: one two three four
one
two
three
four
Type your second string: apple banana pear
apple
banana
pear
The largest word is: banana

separating a string to a double array with seperators

i want to make a function that returns an array of doubles from a specific string.
i've tried multiple options and did not succeed
i have a given function createWeightsArray and i need to fill it.
the numofgrades will be also given which is helpful
the string will be something like: "30% 40% 50%" and i in need a double array {0.3,0.4,0.5}
this is my latest try:
double* createWeightsArray(char* str, int numOfGrades) {
double *gradesweight;
gradesweight = (double*)malloc(numOfGrades * sizeof(double));
int i = 0, n = 0;
while (*str != '\0') {
while (strchr("%", *str)) ++str;
if (*str == '\0') break;
*(gradesweight + n) = (atof(str) / 100);
n++;
str = strstr(str, "% ");
if (str == NULL) break;
*str = '\0';
++str;
}
return gradesweight;
any help will be apprciated
Check it out.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
double* str2double(char *string, int length)
{
int index = 0;
const char delimitor[2] = "% "; /* Delimintor, used the break the string */
char *token;
double *array = malloc(sizeof(double) * length);
if (array == NULL){
fprintf(stderr, "Failed to allocate memory \n");
return NULL;
}
/* get the first token */
token = strtok(string, delimitor);
/* walk through other tokens */
for( index=0; token != NULL && index < length ; index++)
{
array[index] = strtod(token, &token) / 100;
token = strtok(NULL, delimitor);
}
return array;
}
int main()
{
char str[] = "30% 40% 80% 60%";
double *ptr = str2double(str, 4);
if (ptr != NULL) {
for (int i = 0; i < 4; i++)
printf( "%f\n", ptr[i]);
}
return 0;
}
You can use strtoklike this
double* createWeightsArray(char* str1, int numOfGrades) {
double *gradesweight;
char *str =strdup(str1);
gradesweight = (double*)malloc(numOfGrades * sizeof(double));
int i = 0;
*gradesweight = atof(strtok(str,"%"))/100;
i++;
while (--numOfGrades) {
*(gradesweight+i) = atof(strtok(NULL,"%") )/100;
i++;
}
return gradesweight;
}
As you are certain that numOfGrades are provided so better check for zero value of numberOfGrades before calling this function.

how to find duplicate string in an array of strings

I have an array of string from which i have to find duplicate string and then remove that duplicate string like i have string
char aa[50]="Amit Hanish Mahesh Amit"
Now Amit is duplicate and have to remove it from string .
#include "string.h"
main()
{
char x[100] = "Amit Hanish Mahesh Amit";
char y[3][100];
int i = 0, k = 0, j = 0, c = 0, end, t;
int current = 1;
while (x[i] != '\0') {
if (x[i] != ' ') {
y[k][j] = x[i];
j++;
i++;
} else {
// c = c + 1;
i++;
k++;
j = 0;
}
y[k][j] = '\0';
}
for (end = 1; end <= 3; end++) {
for (t = 0; t < end; t++) {
if (strcmp(y[end], y[t]) == 0) break;
}
if (end == t) {
strcpy(y[current],y[t]);
current++;
}
}
y[current] = 0;
printf("%s",y);
}
I have written a smalll routine for it .Does not seems to be worked .Any one have any suggestion where i am going wrong?
The other answers you got work fine for a small number strings (your example code only has 4). But, if you're comparing a large number this will be quite slow since you're doing n^2 comparisons. I'd suggest first splitting the string into an array of strings, then sorting the array using qsort(). In a sorted array all duplicates are guaranteed to be adjacent. This reduces the time from n^2 to n log n -- the time required to sort.
I would split the string array using strtok (see the man page).
So I would have something like this
char x[100]="Amit Hanish Mahesh Amit";
/* Preparing the result string */
size_t sz_result = sizeof(char) * (strlen(x) + 1);
char* result = (char*) malloc( sz_result );
result[0] = '\0';
/* Parsing the string from one element to the other */
char* elm = strtok(x, " ");
while( (elm = strtok(NULL, " ")) != NULL )
{
...
You will have each element of the string to verify if they are unique.
Then I would use something like a hashmap (you can use the one from the glib) or I would put the read string element in a new string only if it is not already in.
Here is an example for the second solution:
...
/* Is the element already in the result string? */
if ( strstr(result, elm) == NULL )
{
/* Then we should add it */
snprintf( result, sz_result - 1, "%s %s", result, elm );
}
}
In the end if you want x to be modified, you simply copy result in x:
strncpy( x, result, 99 );
Here is a sample code (not optimised, not using the strn* primitives, etc.)
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char x[100]="Amit Hanish Mahesh Amit";
/* Preparing the result string */
size_t sz_result = sizeof(char) * (strlen(x) + 1);
char* result = (char*) malloc( sz_result );
result[0] = '\0';
/* Parsing the string from one element to the other */
char* elm = strtok(x, " ");
if (elm != NULL) strcpy(result, elm);
while( (elm = strtok(NULL, " ")) != NULL )
{
/* Is the element already in the result string? */
if ( strstr(result, elm) == NULL )
{
/* Then we should add it */
strcat( result, " " );
strcat( result, elm );
}
}
strcpy( x, result );
fprintf( stdout, "Result: %s\n", x );
}
To remove duplicates from an array without preserving the order of elements:
sort the array
copy unique elements to the beginning of the array
remove the tail with duplicate elements
int remove_duplicates(StringArray array) {
if (! (array and array->items)) return 0; // empty array or NULL
StringArray_sort(array); // sort
// unique_copy()
String result = array->items, last = array->items + array->size;
for (String first = array->items; first != last; ++result) {
String_copy(result, first); // copy first to result
for (String prev = first; ++first != last and String_cmp(prev, first) == 0;)
{ /* skip adjacent equal items */ }
}
// shrink
return StringArray_remove(array, result, last);
}
Example
int main() {
char text[] = "Mahesh Amit Hanish Amit";
StringArray array = split(text, sizeof(text));
StringArray_dump(array, "<"); // print array before removing duplicates
if (remove_duplicates(array) < 0)
perror("error remove_duplicates(), OS error if any");
StringArray_dump(array, ">"); // print it after
StringArray_destroy(array);
return 0;
}
Where split() is:
StringArray split(const char* text, size_t size) {
if (! (text and text[size-1] == '\0')) return NULL;
StringArray array = StringArray_create();
if (! array) return NULL;
size_t n = -1;
for (const char* p = text; p != text+size; p += n+1) {
n = strcspn(p, " \t\n"); // find index of the next whitespace
if (n == 0) continue; // skip consecutive whitespace
// append characters in range [p, p+n)
// as a string to the array
const String string = String_create(p, n);
if (StringArray_append(array, string) < 0) {
String_destroy(string);
StringArray_destroy(array);
return NULL;
}
String_destroy(string);
}
return array;
}
Output
Mahesh<Amit<Hanish<Amit<
Amit>Hanish>Mahesh>
Full source code
I'm pretty sure, that the following line is not intended (assignment, not comparison)
if (end = t) {
See what happens, if you code a == and come back, if you still have problems.
Hint: Always code blanks around operators, so expressions are easier to read.
It's always fun to try to solve this kind of simple problems in C as exercise. Here's my take.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* strstrn(const char *haystack, const char *needle, size_t needle_len)
{
while((haystack = strchr(haystack, *needle)))
{
if (strncmp(haystack, needle, needle_len) == 0)
return (char *) haystack;
haystack++;
}
return NULL;
}
char* find_duplicate(const char* str, size_t len, size_t dup_len)
{
for(size_t i = 0; i < (len - dup_len); i++)
{
char* r = strstrn(str + i + 1, str + i, dup_len);
if(r) return r;
}
return NULL;
}
int main(int argc, char** argv)
{
if(argc < 3)
{
fprintf(stderr, "Usage: %s haystack dup_size\n", argv[0]);
return 1;
}
char* haystack = argv[1];
size_t len = atoi(argv[2]);
char* r;
while((r = find_duplicate(haystack, strlen(haystack), len)))
{
strcpy(r, r + len);
}
puts(haystack);
return 0;
}
/*
* C Program to Find the Frequency of Every Word in a
* given String
*/
#include <stdio.h>
#include <string.h>
void main()
{
int count = 0, c = 0, i, j = 0, k, space = 0;
char str[100], p[50][100], str1[20], ptr1[50][100];
printf("Enter the string\n");
scanf(" %[^\n]s", str);
printf("string length is %d\n", strlen(str));
for (i = 0;i<strlen(str);i++)
{
if ((str[i] == ' ')||(str[i] == ', ')||(str[i] == '.'))
{
space++;
}
}
for (i = 0, j = 0, k = 0;j < strlen(str);j++)
{
if ((str[j] == ' ')||(str[j] == 44)||(str[j] == 46))
{
p[i][k] = '\0';
i++;
k = 0;
}
else
p[i][k++] = str[j];
}
k = 0;
for (i = 0;i <= space;i++)
{
for (j = 0;j <= space;j++)
{
if (i == j)
{
strcpy(ptr1[k], p[i]);
k++;
count++;
break;
}
else
{
if (strcmp(ptr1[j], p[i]) != 0)
continue;
else
break;
}
}
}
for (i = 0;i < count;i++)
{
for (j = 0;j <= space;j++)
{
if (strcmp(ptr1[i], p[j]) == 0)
c++;
}
printf("%s -> %d times\n", ptr1[i], c);
c = 0;
}
}

Resources