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 6 years ago.
Improve this question
I'm trying to write a program that sorts numbers alphabetically in C.
Example Input:
2 35 6 8 4
Example Output:
8 4 6 35 2
Digits should be sorted corresponding to the words representing them, like:
1-one
2-two
3-three
4-four
5-five
6-six
7-seven
8-eight
9-nine
I'm able to sort single digits using switch cases. What is the best way to sort two or more digits?
One way, not most efficient would be: (Will give you just hints to solve the problem and not complete solution)
Use sprintf to convert numbers to string and store in an array of string. If you want to convert numbers to spelling, use this excellent tutorial. (pops on top of the google search)
Sort the string using qsort with below comparision function. Use a struct with number tagged with string if you want the number back.
Comparision function
static int
cmpstringp(const void *p1, const void *p2)
{
return strcmp(* (char * const *) p1, * (char * const *) p2);
}
[Optional] Extract the numbers back from the tag.
Any time you need to sort collections of related data by one value or another, you should be thinking struct. A structure holding each of the various values, (int value, char * of integer, and char * word for integer), can be sorted on any of them and provide you a way to correlate your values regardless of the sort order.
You basic challenge is to fill an array of struct with each of the values, sort on the char * word for integer, and then use it as you need. The various conversions are fairly straight forward, (1) convert the int to its char * equivalent (basically the opposite of itoa); and (2) use the lookup table to concatenate your word equivalents based on each digit in (1). (no need to leave a space between the word digits, unless you just feel like it)
Look over the following example. It is just one way to do what you are trying to do. Let me know if you have an questions:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum {MAXC = 32, MAXW = 64};
/* struct holding both integer and number strings */
typedef struct bs {
int v;
char buf[MAXC];
char str[MAXW];
} bs;
const char *numbers[] = { "zero", /* string lookup */
"one",
"two",
"three",
"four",
"five",
"six",
"seven",
"eight",
"nine" };
char *l2str (long v, char *str, size_t *l);
static int cmpbsp (const void *p1, const void *p2);
int main (void) {
int array[] = {2, 35, 6, 8, 4};
int i, n = sizeof array/sizeof *array;
bs bufstr[n]; /* array of struct */
size_t len = 0;
memset (bufstr, 0, n * sizeof *bufstr); /* initialize to zero */
for (i = 0; i < n; i++) { /* for each in array */
bufstr[i].v = array[i]; /* fill integer val */
l2str (array[i], bufstr[i].buf, &len); /* convert to str */
char *p = bufstr[i].buf;
for (; *p; p++) /* concatenate number for each digit */
strcat (bufstr[i].str, numbers[*p - '0']);
}
for (i = 0; i < n; i++) /* print original sort order */
printf (" bufstr[%d] v : %2d buf : %2s str : %s\n",
i, bufstr[i].v, bufstr[i].buf, bufstr[i].str);
putchar ('\n');
qsort (bufstr, n, sizeof *bufstr, cmpbsp); /* qsort on str */
for (i = 0; i < n; i++) /* print integers alpha-sorted on numbers */
printf (" bufstr[%d] v : %2d buf : %2s str : %s\n",
i, bufstr[i].v, bufstr[i].buf, bufstr[i].str);
putchar ('\n');
return 0;
}
/** convert long to string reversing digits in place.
* base 10 conversion of long value 'v' to string 'str'
* with string length returned through 'l'. 'd' is a
* pointer to the first digit in 'str' used to reverse
* the order of the digits in 'str' in place.
*/
char *l2str (long v, char *str, size_t *l)
{
if (!str) return NULL;
char *d, *p;
char tmp;
/* initialize pointers & length */
d = p = str;
*l = 0;
/* handle negative */
if (v < 0) {
*p++ = '-';
v = -v;
d++;
}
/* convert to char, terminate */
while (v > 0) {
*p++ = (v % 10) + '0';
v /= 10;
}
*p = 0;
*l = (size_t)(p - str);
/* reverse digits in place */
while (--p > d) {
tmp = *p;
*p-- = *d;
*d++ = tmp;
}
return str;
}
/* simple struct compare based on str */
static int cmpbsp (const void *p1, const void *p2)
{
return strcmp (((bs *)p1)->str, ((bs *)p2)->str);
}
Output
The original order and then alpha-sorted order (based on one, two, ...) are shown below.
$ ./bin/alphasortintarray
bufstr[0] v : 2 buf : 2 str : two
bufstr[1] v : 35 buf : 35 str : threefive
bufstr[2] v : 6 buf : 6 str : six
bufstr[3] v : 8 buf : 8 str : eight
bufstr[4] v : 4 buf : 4 str : four
bufstr[0] v : 8 buf : 8 str : eight
bufstr[1] v : 4 buf : 4 str : four
bufstr[2] v : 6 buf : 6 str : six
bufstr[3] v : 35 buf : 35 str : threefive
bufstr[4] v : 2 buf : 2 str : two
note: as mentioned in the comment where you are provided a link to convert numbers to words, you can improve the conversion by adding teens, and tens powers (e.g. thirteen, thirty, etc..) with just a bit of additional effort.
Related
I have a char string containing hexadecimal characters (without 0x or \x):
char *A = "0a0b0c";
from which I want to obtain
const char *B = "\x0a\x0b\x0c";
Is there an efficient way to do this? Thanks!
EDIT: To be clear, I want the resultant string to contain the 3 characters \x0a, \x0b, \x0c, not a 12 character string that says "\x0a\x0b\x0c" where the \ and x are read as individual characters.
This is what I have tried:
const char *B[12];
for (j = 0; j < 4; ++j) {
B[4 * j + 0] = '\\';
B[4 * j + 1] = 'x';
B[4 * j + 2] = A[2 * j];
B[4 * j + 3] = A[2 * j + 1];
};
B[12] = '\0';
which gives me a 12 character string "\x0a\x0b\x0c", but I want B to be as if it was assigned thus:
const char *B = "\x0a\x0b\x0c";
There are multiple confusions in your code:
the input string has 6 characters and a null terminator
the output string should be defined as const char B[3]; or possibly const char B[4]; if you intend to set a null terminator after the 3 converted bytes.
the definition const char *B[12]; in your code defines an array of 12 pointers to strings, which is a very different beast.
The for is fine, but it does not do what you want at all. You want to convert the hexadecimal encoded values to byte values, not insert extra \ and x characters.
the trailing ; after the } is useless
you set a null terminator at B[12], which is beyond the end of B.
Here is a corrected version using sscanf:
const char *A = "0a0b0c";
const char B[4] = { 0 };
for (j = 0; j < 3; j++) {
sscanf(&A[j * 2], "%2hhx", (unsigned char *)&B[j]);
}
The conversion format %2hhx means convert at most the first 2 bytes at A[j * 2] as an unsigned integer encoded in hexadecimal and store the resulting value into the unsigned char at B[j]. The cast is only necessary to avoid a compiler warning.
You can write a function that would sprintf the desired into a string, and then concat that with the destination string.
Something along these lines...
#include <stdio.h>
#include <string.h>
void createB (char B[10], const char *start)
{
char temp[10];
sprintf(temp, "\\x%c%c", start[0], start[1]);
strcat(B, temp);
}
int main ()
{
char A[] = "0a0b0c";
char B[10] = {'\0'};
for (int i=0; A[i] != '\0'; i = i+2)
{
createB(B, A+i);
}
printf("%s\n", B);
return 0;
}
$ ./main.out
\x0a\x0b\x0c
You can modify that to suit your needs or make it more efficient as you feel.
Please make edits as you please; to make it safer with necessary checks. I have just provided a working logic.
If you simply want to add "\x" before each '0' in the string-literal A with the result in a new string B, a simple and direct loop is all that is required, and storage in B sufficient to handle the addition for "\x" for each '0' in A.
For example:
#include <stdio.h>
#define MAXC 32
int main (void) {
char *A = "0a0b0c",
*pa = A,
B[MAXC],
*pb = B;
do { /* loop over all chars in A */
if (*pa && *pa == '0') { /* if chars remain && char is '0' */
*pb++ = '\\'; /* write '\' to B, adv ptr */
*pb++ = 'x'; /* write 'x' to B, adv ptr */
}
*pb++ = *pa; /* write char from A, adv ptr */
} while (*pa++); /* while chars remain (writes nul-termining char) */
puts (B); /* output result */
}
You cannot simply change A to an array with char A[] = 0a0b0c"; and then write back to A as there would be insufficient space in A to handle the character addition. You can always declare A large enough and then shift the characters to the right by two for each addition of "\x", but it makes more sense just to write the results to a new string.
Example Use/Output
$ ./bin/straddescx
\x0a\x0b\x0c
If you need something different, let me know and I'm happy to help further. This is probably one of the more direct ways to handle the addition of the character sequence you want.
#include <stdio.h>
int main(void)
{
char str1[] = "0a0b0c";
char str2[1000];
int i, j;
i = j = 0;
printf("sizeof str1 is %d.\n", sizeof(str1)-1);
for(i = 0; i < sizeof(str1)-1; i += 2)
{
str2[j] = '\\';
str2[j+1] = 'x';
str2[j+2] = str1[i];
str2[j+3] = str1[i+1];
j+=4;
}
str2[j] = '\0';
printf("%s\n", str2);
return 0;
}
I think you can do like this.
Assuming no bad input, assuming 'a' to 'f' are sequentially in order, assuming no uppercase:
// remember to #include <ctype.h>
char *input = "0a0b0c";
char *p = input;
while (*p) {
v = (isdigit((unsigned char)*p) ? *p-'0' : *p-'a'+10) * 16;
p++;
v += isdigit((unsigned char)*p) ? *p-'0' : *p-'a'+10;
p++;
printf("0x%d", v); // use v
}
While using char A[] = "0a0b0c";, as proposed by kiran, would make it possible to change the string, it wil not yet allow to insert characters. Because that would make the string longer and hence not fit into the available memory. This in turn is a problem, if you cannot create the target string right away with the needed size.
You could know the needed size in advance, if the input is always of the same length and always requires the same number of inserted characters, e.g. if like in your example, the target string is double the size of the input string. For a simple character array definition, you would need to know the size already at compile time.
char A[7] = "0a0b0c"; /* not 6, because size for the termianting \0 is needed */
char B[13] = ""; /* 2*6+1 */
So you can stay with char *A = "0a0b0c"; and make your life easier by setting up memory of appropriate size to serve as target. For that you need to first determine the length of the needed memory, then allocate it.
Determining the size if easy, if you know that it will be twice the input size.
/* inside a function, this does not work as a variable definition */
int iLengthB = 2*length(A);
char* B = malloc(iLengthB+1); /* mind the terminator */
Then loop over A, copying each two characters to B, prepending them with the two characters "\x". I assume that this part is obvious to you. Otherwise please show how you setup the program as described above and make a loop outputting each character from A separatly. Then, after you demonstrated that effort, I can help more.
As an Example,
Input:
c[] = "[1,2,3][5,7,8]"
Output:
a = [1,2,3] //of type int a[]
b = [5,7,8] //of type int b[]
I have tried using strtok to remove "]". But, when I use strtok next time, I am not able to use it. If I try to print the output, I get
[1,2,3
[1
2
3
instead of
[1,2,3
[1
2
3
[5,7,8
[5
7
8
Code that I have so far
char c[] = "[1,2,3][5,7,8]";
char *token = strtok(c, "]");
for (token; token != NULL ; token = strtok(NULL, "]")){
puts(token);
char *comma = strtok(c, ",");
for (comma; comma != NULL; comma = strtok(NULL, ",")){
puts(comma);
}
}
Your problem is, that strtok has a memory. First time that you pass in a string, it is remembered and then used again and again as long as you pass in NULL as first parameter.
However, within your loop, you call strtok again with a parameter. So this new string (which is the first token only) is placed in strtok's memory, and after it is processed completely in the inner loop, there is nothing left to tokenize in the outer loop.
Have a look at this thread, it explains more detailed how strtok works.
However, you are lucky: strtok is manipulating the string you first passed in place (this is why you have to pass the string to be tokenized as char*, but the delimiters can be a const char*). So you can do this:
char c[] = "[1,2,3][5,7,8]";
char* next = c;
char* token;
while((token = strtok(next, "]")))
{
puts(token);
next += strlen(token) + 1; // move next behind the token
token = strtok(token, ",");
do
{
puts(token);
}
while((token = strtok(NULL, ",")));
}
If you are wondering about the extra parentheses, these are to prevent a warning in the compiler ("possible assignment instead of comparison").
If you are converting a string of character digits to an array of integer values, one character per value (or allowing a - before any character digit to indicate a negative value for your array), you may be better off writing a simple function to step though the string and perform your conversions manually.
An example using array indexing of the string could be written a follows. You could easily change the array index notations to pointer notation which is more intuitive to some.
#include <stdio.h>
#include <string.h>
size_t str2arr (char *d, size_t max, char *s, size_t *ofs);
int main (int argc, char **argv) {
char c[] = "[1,2,3][5,7,8]";
char *p = argc > 1 ? argv[1] : c;
size_t i, offset = 0, na = 0, nb = 0, nchr = strlen (p);
char a[nchr], b[nchr];
memset (a, 0, nchr * sizeof *a); /* zero each VLA */
memset (b, 0, nchr * sizeof *b);
na = str2arr (a, nchr, p, &offset); /* convert first segment */
nb = str2arr (b, nchr, p + offset, &offset); /* convert second segment */
for (i = 0; i < na; i++) /* output results */
printf (" a[%2zu] : % d\n", i, a[i]);
putchar ('\n');
for (i = 0; i < nb; i++)
printf (" b[%2zu] : % d\n", i, b[i]);
putchar ('\n');
return 0;
}
/** convert a string of characters to an array of values
* including accounting for negative values. the destination
* index `di` returns the number of characters conversions, the
* offset of the next segment within 's' is updated in pointer 'ofs'
*/
size_t str2arr (char *d, size_t max, char *s, size_t *ofs)
{
if (!d || !s || !*s) return 0; /* validate input */
size_t di = 0, neg = 0;
register size_t si = 0;
for (; di < max && s[si]; si++, di++) { /* for each character */
if (s[si] == ']') break;
while (s[si] && (s[si] < '0' || ('9' < s[si]))) { /* if not digit */
if (s[si] == '-') neg = 1; /* if '-' sign, set flag */
else neg = 0; /* clear if not last before digit */
si++;
}
if (!s[si]) break; /* validate not end of string */
d[di] = neg ? -(s[si] - '0') : s[si] - '0'; /* convert to digit */
neg = 0; /* reset flag */
}
*ofs = si + 1; /* update offset before return */
return di; /* return number of conversions */
}
Example Use/Output
$ ./bin/str2arr
a[ 0] : 1
a[ 1] : 2
a[ 2] : 3
b[ 0] : 5
b[ 1] : 7
b[ 2] : 8
$ ./bin/str2arr "[1,2,3,4][5,6,-5,7,-1,8,9,2]"
a[ 0] : 1
a[ 1] : 2
a[ 2] : 3
a[ 3] : 4
b[ 0] : 5
b[ 1] : 6
b[ 2] : -5
b[ 3] : 7
b[ 4] : -1
b[ 5] : 8
b[ 6] : 9
b[ 7] : 2
Look it over, compare this approach to the other answers. In C, you have as much fine-grain-control over how you parse data as you want to exercise. If you have no need to handle negative values, then the implementation is much simpler. Let me know if you have any questions.
This solution has two nested loops of strtok_s, because strtok is not re-entrant. This is MSVC, some systems implement the similar strtok_r.
I have created output in accordance with the top of your question, this can be modified to suit other output, it was not very clear. In this case, it was not really necessary to have two nested loops, but your subsequent examples confuse the issue by breaking up the comma'ed input.
#include <stdio.h>
#include <string.h>
int main(void) {
char c[] = "[1,2,3][5,7,8]";
char *tok1 = NULL;
char *tok2 = NULL;
char *end1 = NULL;
char *end2 = NULL;
int comma = 0;
char identifier = 'a';
tok1 = strtok_s(c, "[]", &end1);
while(tok1 != NULL) { // outer loop splitting [bracket] parts
printf("%c = [", identifier);
comma = 0; // control comma output
tok2 = strtok_s(tok1, ",", &end2);
while(tok2 != NULL) { // inner loop splitting ,comma, parts
if(comma) { // check if comma required
printf(",");
}
printf("%s", tok2);
comma = 1; // a comma will be needed
tok2 = strtok_s(NULL, ",", &end2);
}
printf("] //of type int %c[]\n", identifier);
identifier++;
tok1 = strtok_s(NULL, "[]", &end1);
}
return 0;
}
The simpler program where you don't need to examine within the [brackets] is
#include <stdio.h>
#include <string.h>
int main(void) {
char c[] = "[1,2,3][5,7,8]";
char *tok = NULL;
char identifier = 'a';
tok = strtok(c, "[]");
while(tok != NULL) {
printf("%c = [%s] //of type int %c[]\n", identifier, tok, identifier);
identifier++;
tok = strtok(NULL, "[]");
}
return 0;
}
In both cases the output is:
a = [1,2,3] //of type int a[]
b = [5,7,8] //of type int b[]
EDIT altered the second example to give output as per OP's recent comment above.
#include <stdio.h>
#include <string.h>
int main(void) {
char c[] = "[1,2,3][5,7,8]";
char *tok = NULL;
char identifier = 'a';
tok = strtok(c, "[]");
while(tok != NULL) {
printf("int %c[] = { %s };\n", identifier, tok, identifier);
identifier++;
tok = strtok(NULL, "[]");
}
return 0;
}
Program output:
int a[] = { 1,2,3 };
int b[] = { 5,7,8 };
I have two strings that I would like to combine, removing duplicate substrings. Note that every two consecutive numbers constitute a substring. Consider string str1 and str2:
str1 = "#100#123#100#678"
str2 = "#100#678#100#56"
I would like to produce a combined string as:
comboStr = "#100#123#100#678#100#56" (i.e. I removed the duplicate #100#678)
What's the easiest way to do this? Is there a way I can achieve this using regular expressions?
I don't think regular expressions are a good way to solve this problem. Regexes might be useful in finding the #123 tokens, but the problem needs to backtrack on its own string in a way regex's back references are not desiged for.
I also don't think that there is an easy way (as in three lines of code) to solve this.
I assume that the strings always follow the pattern (#\d+)* and that the pair created at the seam when joining two strings is not trated as special, i.e. the resulting pair might be considered as duplicate. This means we can separate concatenation from pair removal.
Convert your string to a list of integers, operate on these lists and then join them back. That's some work, but it makes the actual code to strip duplicates easier - it's complicated enough - and might also come in handy when you need to operate on similar strings often.
#include <stdlib.h>
#include <stdio.h>
/*
* Convert a string to a list of at most max integers. The
* return value is the number of integers in the list (which
* max be greater than max!) or -1 if the string is invalid.
*/
int ilist_split(int *ilist, int max, const char *str)
{
const char *p = str;
int n = 0;
while (*p) {
int x;
int pos;
if (sscanf(p, "#%d %n", &x, &pos) < 1) return -1;
if (n < max) ilist[n] = x;
n++;
p += pos;
}
return n;
}
/*
* Convert a list of integers back to a string. The string
* is at most nbuf - 1 characters long and is assured to be
* zero-terminated if nbuf isn't 0. It is legal to pass NULL
* as char buffer if nbuf is 0. Returns the number of characters
* that would have been written ha dthe buffer been long enough,
* snprintf-style.
*/
int ilist_join(const int *ilist, int n, char *buf, int nbuf)
{
int len = 0;
int i;
for (i = 0; i < n; i++) {
len += snprintf(buf + len,
nbuf > len ? nbuf - len : 0, "#%d", ilist[i]);
}
return len;
}
/*
* Auxliary function to find a pair in an inteher list.
*/
int ilist_find_pair(int *ilist, int n, int a1, int a2)
{
int i;
for (i = 1; i < n; i++) {
if (ilist[i - 1] == a1 && ilist[i] == a2) return i - 1;
}
return -1;
}
/*
* Remove duplicate pairs from an integer list. The first
* pair is kept, subsequent pairs are deleted. Returns the
* new length of the array.
*/
int ilist_remove_dup_pairs(int *ilist, int n)
{
int i, j;
j = 1;
for (i = 1; i < n; i++) {
int a1 = ilist[i - 1];
int a2 = ilist[i];
if (ilist_find_pair(ilist, i - 1, a1, a2) < 0) {
ilist[j++] = ilist[i];
} else {
i++;
}
}
return j;
}
#define MAX 40
int main()
{
const char *str1 = "#100#123#100#678";
const char *str2 = "#100#678#100#56";
char res[80];
int ilist[MAX];
int nlist;
/* convert str1 */
nlist = ilist_split(ilist, MAX, str1);
if (nlist > MAX) nlist = MAX;
/* convert and concatenate str2 */
nlist += ilist_split(ilist + nlist, MAX - nlist, str2);
if (nlist > MAX) nlist = MAX;
/* remove duplicate pairs */
nlist = ilist_remove_dup_pairs(ilist, nlist);
/* convert back to string */
ilist_join(ilist, nlist, res, sizeof(res));
printf("%s\n", res);
return 0;
}
I want to convert a section of a char array to a double. For example I have:
char in_string[] = "4014.84954";
Say I want to convert the first 40 to a double with value 40.0. My code so far:
#include <stdio.h>
#include <stdlib.h>
int main(int arg) {
char in_string[] = "4014.84954";
int i = 0;
for(i = 0; i <= sizeof(in_string); i++) {
printf("%c\n", in_string[i]);
printf("%f\n", atof(&in_string[i]));
}
}
In each loop atof it converts the char array from the starting pointer I supply all the way to the end of the array. The output is:
4
4014.849540
0
14.849540
1
14.849540
4
4.849540
.
0.849540
8
84954.000000 etc...
How can I convert just a portion of a char array to a double? This must by modular because my real input_string is much more complicated, but I will ensure that the char is a number 0-9.
The following should work assuming:
I will ensure that the char is a number 0-9.
double toDouble(const char* s, int start, int stop) {
unsigned long long int m = 1;
double ret = 0;
for (int i = stop; i >= start; i--) {
ret += (s[i] - '0') * m;
m *= 10;
}
return ret;
}
For example for the string 23487 the function will do this calculations:
ret = 0
ret += 7 * 1
ret += 8 * 10
ret += 4 * 100
ret += 3 * 1000
ret += 2 * 10000
ret = 23487
You can copy the desired amount of the string you want to another char array, null terminate it, and then convert it to a double. EG, if you want 2 digits, copy the 2 digits you want into a char array of length 3, ensuring the 3rd character is the null terminator.
Or if you don't want to make another char array, you can back up the (n+1)th char of the char array, replace it with a null terminator (ie 0x00), call atof, and then replace the null terminator with the backed up value. This will make atof stop parsing where you placed your null terminator.
Just use sscanf. Use the format "ld" and check for return value is one.
What about that, insert NULL at the right position and then revert it back to the original letter? This means you will manipulate the char array but you will revert it back to the original at the end.
You can create a function that will make the work in a temporary string (on the stack) and return the resulting double:
double atofn (char *src, int n) {
char tmp[50]; // big enough to fit any double
strncpy (tmp, src, n);
tmp[n] = 0;
return atof(tmp);
}
How much simpler could it get than sscanf?
#include <assert.h>
#include <stdio.h>
int main(void) {
double foo;
assert(sscanf("4014.84954", "%02lf", &foo) == 1);
printf("Processed the first two bytes of input and got: %lf\n", foo);
assert(sscanf("4014.84954" + 2, "%05lf", &foo) == 1);
printf("Processed the next five bytes of input and got: %lf\n", foo);
assert(sscanf("4014.84954" + 7, "%lf", &foo) == 1);
printf("Processed the rest of the input and got: %lf\n", foo);
return 0;
}
I made a small function that fills an allocated block of memory containing every position of a given char within a given string and returns a pointer to the memory block.
The only problem with this function is that there is no way to check the size of the memory block; so I also made a function that counts the occurrence of a given char within a string.
Here is an example of use:
/*count occurences of char within a given string*/
size_t strchroc(const char *str, const char ch)
{
int c = 0;
while(*str) if(*(str++) == ch) c++;
return c;
}
/*build array of positions of given char occurences within a given string*/
int *chrpos(const char *str, const char ch)
{
int *array, *tmp, c = 0, i = 0;
if(!(array = malloc(strlen(str) * sizeof(int)))) return 0x00;
while(str[c])
{
if(str[c] == ch) array[i++] = c;
c++;
}
if(!(tmp = realloc(array, i * sizeof(int)))) return 0x00;
array = tmp;
return array;
}
int main(void)
{
char *str = "foobar foobar"; //'o' occurs at str[1], str[2], str[8], and str[9]
int *array, b = 0, d;
if(!(array = chrpos(str, 'o'))) exit(1); //array[0] = 1, array[1] = 2, array[2] = 8, array[3] = 9
/*
* This is okay since I know that 'o'
* only occures 4 times in str. There
* may however be cases where I do not
* know how many times a given char
* occurs so I figure that out before
* utilizing the contents of array.
* I do this with my function strchroc.
* Below is a sample of how I would
* utilize the data contained within
* array. This simply prints out str
* and on a new line prints the given
* char's location within the str
* array
*/
puts(str);
while(b < (int) strchroc(str, 'o')) //loop once for each 'o'
{
for(d = 0; d < (b == 0 ? array[b] : array[b] - array[b - 1] - 1); d++) putc((int) ' ', stdout);
printf("%d", array[b]);
b++;
}
}
Output:
foobar foobar
12 89
My only concern is that if one of these two functions fail, there is no way for the data to be used correctly. I was thinking about making the number of occurrences of char within the string an argument for chrpos but even then I would still have to call both functions.
I was wondering if anybody had any suggestions for a way to do this so that I only need one function to build the array.
The only way I can think of is by storing the number of char occurrences into array[0] and having array[1] through array[char_occurences] holding the positions of char.
If anybody has a better idea I would greatly appreciate it.
As stated in my comment the first thing is to save up the data anyway, in case you can't shrink the allocated memory :
if (!(tmp = realloc(array, i * sizeof(int))))
return array;
return (tmp); //array = tmp; is useless
If you want to protect a bit more your strchroc function add a if (!str) return 0; at the beginning.
You can change your function so that it also "returns" the number of occurrences found. While we cannot actually return multiple values from a function in C, we can pass a pointer as a parameter and have the function write down a value using that pointer:
int *chrpos(const char *str, char ch, int *found) {
/*
...
*/
*found = i;
return array;
}
Note that you don't need the const modifier for ch.