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.
Related
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", ¶meter_1);
printf("\nEnter the delimiter: ");
scanf("%s", ¶meter_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", ¶meter_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;
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I need a help with a program (without using strtok() function) that should be doing this:
If the input is
car;dog;pet;elephant
and if the argument is 2, the ouput should be:
car;pet;elephant
if the argument is 4, the output should be:
car;dog;pet
and so on.
I've tried a lot of different solutions but nothing seems to work. So if anybody could help me, I would be really glad.
Thank you.
I think this solution always works with valid input.
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
if (argc != 3)
return 1;
int x = atoi(argv[2]);
char *s = argv[1], *d = argv[1];
while (*s)
{
if (x == 0)
{
--x;
while (*s && *s != ';')
++s;
if (*s)
++s;
else
break;
}
if (*s == ';')
--x;
*d++ = *s++;
}
if (*(d - 1) == ';')
*(d - 1) = '\0';
else
*d = '\0';
puts(argv[1]);
return 0;
}
Here is a function to construct a new csv line with the field number pos (1-based) removed:
#include <stdlib.h>
#include <string.h>
char *removeField(const char *str, char delim, int pos)
{
char *out;
const char *p, *q;
size_t len1, len2;
int i, nsep = 0;
if (str == NULL)
return NULL;
/* skip the fields before the target field */
for (p = str, i = 1; *p && i < pos; i++) {
while (*p && *p != delim)
p++;
if (*p == delim) {
p++;
nsep++;
}
}
/* skip the field to remove */
for (q = p; *q && *q != delim; q++)
continue;
if (*q == delim) {
/* if there are more fields, skip the delimiter */
q++;
} else {
/* otherwise remove the trailing delimiter if the removed field was
the last one but not the first one */
if (pos > 1 && nsep == pos - 1)
p--;
}
/* allocate the exact amount of bytes */
len1 = p - str;
len2 = strlen(q);
out = malloc(len1 + len2 + 1);
if (out != NULL) {
/* copy the left and right parts */
memcpy(out, str, len1);
memcpy(out + len1, q, len2 + 1);
}
/* return the new CSV line or NULL if allocation failure */
return out;
}
Here is the function removing the substring from the "csv style" line. It takes info the account empty strings and (probably most as I did not properly test it) border cases.
It is not using "heavy" string functions like strtok or strdup as I believe this exercise is to write it using arrays or pointers.
char *dupAndDelete(const char *str, char delim, int pos)
{
char *out = NULL;
int cpos = 1;
if(str)
{
out = malloc(strlen(str) + 1);
char *wrk = out;
if(out)
{
while(*str)
{
if(cpos == pos)
{
while(*str && *str != delim)
str++;
}
else
{
*wrk++ = *str;
}
if(*str == delim)
{cpos++;}
if(*str) str++;
}
if(wrk > out)
if(*(wrk - 1) == delim && cpos == pos)
wrk--;
*wrk = 0;
}
}
return out;
}
int main(void)
{
char *str = ";;car;;dog;pet;elephant;;";
char *output;
for(int pos = 0; pos < 12; pos++)
{
output = dupAndDelete(str, ';', pos);
if(output) printf("pos = %2d str = \"%s\"\n", pos, output);
fflush(stdout);
free(output);
}
return 0;
}
You can search a ; with strchr()
This code searches the index you want to remove (1-based indexes)
int main(void)
{
for (size_t i = 0; i < 6; i++)
{
// This is you argument
int arg2 = i;
printf("%ld: ", i);
char *s = strdup(";car;dog;pet;elephant");
char *curr = s;
for (int i = 0; curr && i < arg2; i++)
curr = strchr(curr + 1, ';');
if (!curr)
{
printf("%s\n", s);
free(s);
continue;
}
char *next = strchr(curr + 1, ';');
if (!next)
{
*curr = 0;
}
else
{
size_t offset = next - curr;
size_t len = strlen(s);
for (size_t i = curr - s; i < len; i++)
s[i] = (i + offset < len ? s[i + offset + (curr == s)] : 0);
}
printf("%s\n", s);
free(s);
}
return 0;
}
Without any control/argument inspection, I think this is what you're looking for:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char ** argv) {
if (argc < 3) {
printf("Argument missing!\n");
return 1;
}
char * output = calloc(sizeof(char), strlen(argv[1]));
int cnt = 1;
int memb = atoi(argv[2]);
int outputp = 0;
char* token = strtok(argv[1], ";");
while (token != NULL) {
if (cnt != memb) {
strcat(output+outputp, token);
outputp += strlen(token);
strcat(output+outputp, ";");
outputp++;
}
token = strtok(NULL, ";");
cnt++;
}
output[outputp-1] = '\0';
printf("%s\n", output);
free(output);
return 0;
}
use:
$ ./a.out "car;dog;pet;elephant" 2
car;pet;elephant
$ ./a.out "car;dog;pet;elephant" 4
car;dog;pet
Edit: you can use strsep() instead of strtok(), then if your substring is empty, that will counts too:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char ** argv) {
if (argc < 3) {
printf("Argument missing!\n");
return 1;
}
char * output = calloc(sizeof(char), strlen(argv[1])+1);
int cnt = 1;
int memb = atoi(argv[2]);
int outputp = 0;
char * token;
while ((token = strsep(&argv[1], ";")) != NULL) {
printf("'%s'\n", token);
if (cnt != memb) {
strcat(output+outputp, token);
outputp += strlen(token);
strcat(output+outputp, ";");
outputp++;
}
cnt++;
}
output[outputp-1] = '\0';
printf("%s\n", output);
free(output);
return 0;
}
I am supposed to save every sequence of digits from a string in an array of chars , this is what i tried:
#include<stdio.h>
#include<ctype.h>
#include<string.h>
int check_number(char *s) {
for (; *s; ++s) {
if (!isdigit(*s))
return 0;
}
return 1;
}
void int_in_string(char *s, char **ar, int MaxCap) {
char temp[100];
int index = 0;
int i = 0;
for (; *s; s++) {
if (index == MaxCap) {
break;
}
if (isdigit(*s)) {
temp[i++] = *s;
}
if (*s == ' ' && check_number(temp)) {
ar[index++] = temp;
memset(temp, '\0', i);
i = 0;
}
}
if (index == 0) {
printf("no numbers in string");
}
for (int i = 0; i < index; i++)
printf(" %s \n", ar[i]);
}
but this code only prints several newlines , can someone explain me what i do wrong?
Some issues:
ar[index++]=temp;
This is just storing the same value (the address of temp) over and over. What you need to do is copy the string into the array.
Also, you need to terminate the string temp with '\0'. You handle this in all but the first string with memset(temp, '\0', i); However, since local variables are not initialized, you need to do it:
char temp[100] = {0}
Or, you can remove the initialization and the memset by just adding the EOS:
temp[i] = '\0';
Lastly, since you declare the original array as
char * ar[10];
You are not allocating any space for the strings. The simplest way to handle that is with strdup.
void int_in_string(char *s, char **ar, int MaxCap)
{
char temp[100];
int index = 0;
int i = 0;
for (; *s; s++) {
if (isdigit(*s)) {
temp[i++] = *s;
// Need to avoid buffer overflow
if (i == sizeof(temp)) {
i = 0;
}
}
if (isspace(*s)) {
temp[i] = '\0';
// strdup will allocate memory for the string, then copy it
ar[index++] = strdup(temp);
// if (NULL == ar[index-1]) TODO: Handle no memory error
i = 0;
if (index == MaxCap) {
break;
}
}
}
if (index == 0) {
printf("no numbers in string");
}
for (int i = 0; i < index; i++) {
printf(" %s \n", ar[i]);
// free the mem from strdup
free(ar[i]);
}
}
I believe some systems may not have strdup(). If not, it can be easily replicated:
char * my_strdup(const char *src)
{
if (src == NULL) return NULL;
char *dest = malloc(strlen(src) + 1);
if (dest == NULL) return NULL;
strcpy(dest, src);
return dest;
}
I want to return nothing when the string is number
here is my code,
#include <string.h>
#include <ctype.h>
int num = 0;
char* findWord(char* subString) {
char* word = malloc(sizeof(char) * (strlen(subString) + 1));
int i = 0;
int Position = 0;
num = 0;
while (ispunct(subString[i]) != 0 || isspace(subString[i]) != 0) {
i++;
}
num = i;
while (ispunct(subString[i]) == 0 && isspace(subString[i]) == 0) {
word[Position] = subString[i];
i++;
Position++;
}
word[Position] = '\0';
return word;
}
char** wordList(const char* s) {
int len = strlen(s);
int i = 0;
char* Copyword = malloc(sizeof(char) * len);
strncpy(Copyword, s, len);
char** result = (char**) malloc(sizeof(char*) * (len + 1));
char* word = NULL;
word = findWord(Copyword);
char* wordEnd = Copyword;
while (*word != 0) {
result[i] = word;
wordEnd = wordEnd + strlen(word) + num;
word = findWord(wordEnd);
i++;
}
result[i] = '\0';
free(Copyword);
return result;
}
int main(void) {
char** words = wordList("1 23 456 789");
int i = 0;
while (words[i] != NULL) {
printf("%s\n", words[i]);
free(words[i]); // We're done with that word
i++;
}
free(words); // We're done with the list
return 0;
}
my code is ok when the string is sentence.
however, in this case, I want to print nothing(just like a space) when the string is number.
but what I go is
1
23
456
789
I expect to get
nothing shows here! just a space
For starters: You pass a non 0-terminated C-"string" (Copyword) to findWord() and in there call strlen() on it. This just doesn't crash your app by bad luck.
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;
}
}