How to make a Sentence out of 2D char array using pointers - c

I am newbie at C so please try to be patient if I am not clear enough.
I have an assignment which I need to make a function that gets a squared char matrix and make a string out of it.
The function should return a pointer to a string eventually,
so that in main I can initialize a string with it and print it in the end.
(also i am restricted to use only pointers inside this function and not regular arrays syntax)
for example the matrix is:
R O M E
G O A L
H E A D
D E A D
and i want to make a sentence like that: "ROME GOAL HEAD DEAD".
I tried to make a for loop which runs only on the matrix rows so I could take each row and copy to a string which I already prepared before (with enough space in it) in the first row I used strcpy() and the other strcat().
Nothing happened.
Sorry for my english, and thanks.
char * makeString(char *smallMat, int rows, char *pStr ) {
int i;
char sentence[(rows * rows) + rows + rows];
pStr = &sentence;
for (i = 0; i < rows; ++i) {
if (i == 0) {
strcpy(sentence, *(smallMat + i));
}
else{
strcat(sentence, ' ' + *(smallMat + i));
}
}
return pStr;
}

As #anonmess pointed out, you cannot use strcpy() etc. for non-0-terminated character sequences. As you said yourself, the task is to use pointers. If you used strcpy() (and if it worked), you would work around the assignment ;)
Here is a full solution that does not use pStr.
#include <stdio.h> // printf()
#include <stdlib.h> // malloc()
static char smallMat[4][4] = {
{ 'R', 'O', 'M', 'E' },
{ 'G', 'O', 'A', 'L' },
{ 'H', 'E', 'A', 'D' },
{ 'D', 'E', 'A', 'D' }
};
char* makeString(char* smallMat, int rows) {
int currentRow, currentColumn;
/* space for all characters (rows * rows)
* + one character for each space + terminating '\0'. */
char* sentence = malloc((rows * rows) + rows);
char* p = sentence;
for (currentRow = 0; currentRow < rows; ++currentRow) {
for (currentColumn = 0; currentColumn < rows; ++currentColumn) {
*p++ = *(smallMat + (currentRow * rows) + currentColumn);
}
*p++ = ' ';
}
*--p = '\0'; /* replace the last space with terminating 0,
* so it can be printed. */
return sentence;
}
int main() {
char* output = makeString(smallMat, 4);
printf(output);
free(output);
return 0;
}

The easiest way to go about creating a sentence from your 2D array of SIZE rows and columns of characters is simply to create an array of SIZE * SIZE + SIZE characters to hold the sentence (SIZE * SIZE for each character, plus SIZE - 1 spaces, plus the nul-terminating character)
After declaring an array to hold your sentence, pass both the new array and your 2D array to your makestring() function and loop over each character in the 2D array, adding a space before each word (except for the 1st word) and finally nul-terminate your new array creating a C-string.
You cannot use strcpy (or any other function expecting a C-string) on the row of characters in your 2D array as the rows of characters in your 2D array are not nul-terminated strings. (your 2D array is just that, a 2D array of characters). You must loop over and assign each character to a position within your 1D array.
Putting it altogether, you could write makestring() similar to:
#define SIZE 4
char *makestring (char *str, char (*a)[SIZE])
{
char *p = str; /* a pointer to 1st character in str */
for (int i = 0; i < SIZE; i++) { /* for each row */
if (i) /* if row not 1st */
*p++ = ' '; /* add space */
for (int j = 0; j < SIZE; j++) /* for each char */
*p++ = a[i][j]; /* copy to str */
}
*p = 0; /* nul-terminate string */
return str; /* return pointer to string (for convenient use in-line) */
}
(note: returning a pointer to the beginning of str would allow the function to be used in-line such as: printf ("str: '%s'\n", makestring (str, matrix)); As mentioned, this is just for convenience, you can make the function of type void as you are not allocating and have provided a pointer to an array that will be updated within the function and can be tested back in the caller before use.)
Adding a short test program, you could test your function as follows:
#include <stdio.h>
#define SIZE 4
char *makestring (char *str, char (*a)[SIZE])
{
char *p = str; /* a pointer to 1st character in str */
for (int i = 0; i < SIZE; i++) { /* for each row */
if (i) /* if row not 1st */
*p++ = ' '; /* add space */
for (int j = 0; j < SIZE; j++) /* for each char */
*p++ = a[i][j]; /* copy to str */
}
*p = 0; /* nul-terminate string */
return str; /* return pointer to string (for convenient use in-line) */
}
int main (void) {
char matrix[SIZE][SIZE] = { {'R','O','M','E'}, /* square 2D array */
{'G','O','A','L'},
{'H','E','A','D'},
{'D','E','A','D'} },
str[SIZE * SIZE + SIZE] = ""; /* array to hold sentence */
makestring (str, matrix); /* call makestring */
if (*str != 0) /* validate str not empty-string */
printf ("str: '%s'\n", str); /* output string */
}
Example Use/Output
Running the program would produce:
$ ./bin/makestring
str: 'ROME GOAL HEAD DEAD'
(note: single-quotes added around the string to affirmatively show the beginning and end of the string)
Look things over and let me know if you have further questions.

Related

Add a char padding in C strings

I am trying to implement this simple encryption method for a a list of numbers, the encryption is like this:
we add the 1st element of the list before every element of the entire list of numbers,
if we have:
char array = "356307042441013"
the first number is 3, that means we need to add it before every element of the list of numbers:
'33 35 36 33 30 37 30 34 32 34 34 31 30 31 33'
char result= "333536333037303432343431303133"
is there any function in C that will make the implementation easier ? because I tried doing it with shifting but couldn't get that result.
You can do following:
Step I: Allocate memory of double the size of input and + 1 to accommodate the null character to the result string.
Step II: Iterate through the input string and, in every iteration, first copy the input[0] character to current location of result string and, in very next location of result string, copy the current processing character of input string.
Step III: Once the loop exits, add null character at the end of result string.
[Take special care of empty string because it will have nothing to encrypt]
Implementation:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * encryption (const char * input) {
if ((!input) || (*input == '\0')) {
return NULL;
}
size_t len = strlen (input);
char * temp = malloc ((len * 2) + 1);
if (!temp) {
printf ("Failed to allocate memory\n");
exit (EXIT_FAILURE);
}
size_t i = 0, j = 0;
for (; input[j]; ++j) {
temp[i++] = input[0];
temp[i++] = input[j];
}
temp[i] = '\0';
return temp;
}
int main (void) {
char array[] = "356307042441013";
char * result = encryption (array);
if (result) {
printf ("result : %s\n", result);
// Free the dynamically allocated memory once done with it
free (result);
}
return 0;
}
Output:
# ./a.out
result : 333536333037303432343431303133
A cleaner, more concise solution:
#include <stdio.h>
#include <string.h>
int main()
{
char foo[] = "356307042441013";
char bar[2 * sizeof(foo) - 1];
char *src = foo, *dest = bar;
while (*src) {
*dest++ = foo[0];
*dest++ = *src++;
}
*dest = *src;
printf("foo=%s\n",foo);
printf("bar=%s\n",bar);
return 0;
}
It is better to use foo[] rather than hard-coding the length, because what if you want to change the string. If you use [] (empty brackets) the compiler will allocate exactly how many bytes you need (including the terminating null). Similarly, for bar we base the size on the size of foo by doubling it and subtracting 1 (since the terminating null does not need to be doubled).
I found a way to solve this:
int main() {
char foo[16] = "356307042441013";
char bar[2*16-1];
for (int i = 0; i < 16; i++) {
bar[2*i] = foo[i];
if (i != 16 - 1)
bar[2*i + 1] = foo[0];
}
char res[32]= "3";
strcat(res,bar);
res[30] = '\0';
printf("bar=%s\r\n",bar);
printf("begin=%s\r\n",res);
return 0;
}

strlen() crashes when I call it

I am trying to write a simple piece of code that merges two strings together in even and odd indexes.
This is the code
void two_strings(char a[], char b[]) {
int counta = 0, countb = 0;
int lena = strlen(a);
int lenb = strlen(b);
int lenab = lena + lenb;
char ans[lenab];
for(int i = 0; i<strlen(ans); i++) {
if(i%2 == 0) {
ans[i] = a[counta];
counta++;
}
else {
ans[i] = b[countb];
countb++;
}
}
printf("%s\n", ans);
}
This is the main:
int main() {
char a[] = "hello";
char b[] = "bye";
two_strings(a, b);
return 0;
}
I have compiled it with -Wall and didn't get any warnings or errors, and I have tried it also with long instead of int just to check if that was the issue. when I run the code it doesn't get past the first strlen(a)
Strings in C are defined as a sequence of non-null bytes followed by a terminating null byte ('\0').
The following are equivalent strings
char one[] = "hello";
char two[] = { 'h', 'e', 'l', 'l', 'o', '\0' };
Both of these would have a string length of 5, and occupy 6 bytes of memory.
String handling functions in the Standard Library expect this null-terminating byte, and you will invoke Undefined Behavior by passing a non-null-terminated array to them. strlen and printf (with %s) are examples of these kinds of functions.
In your two_strings function you are not allocating enough memory to store the null-terminating byte. You also make no attempt to place this null-terminating byte in the array.
Allocate an additional byte for the null-terminating byte, and do not attempt to take the string length of an uninitialized array.
void two_strings(char a[], char b[]) {
/* ... */
size_t length = strlen(a) + strlen(b);
char string[length + 1];
for (size_t i = 0; i < length; i++) {
/* ... */
}
string[length] = '\0';
/* ... */
}
Also note that size_t is the correct type to use when dealing with memory indexing, and is the type returned by strlen.
As for your algorithm, in the event where your input strings differ in length you will attempt to continue indexing one of the strings after you have already reached its end.
You will either want to: only take the smaller string's length of characters from the larger string, stopping when the smaller string has been exhausted; or, append the remaining characters of the larger string to the result after the smaller string has been exhausted.
A quick example of the second approach:
#include <stdio.h>
#include <string.h>
void zip_strings(const char *a, const char *b) {
size_t combined_length = strlen(a) + strlen(b);
char joined_string[combined_length + 1];
for (size_t i = 0; i < combined_length; i++) {
const char **src = i & 1 ? &b : &a;
if (!**src)
src = &a;
if (!**src)
src = &b;
joined_string[i] = *((*src)++);
}
joined_string[combined_length] = '\0';
puts(joined_string);
}
int main(int argc, char **argv) {
if (argc > 2)
zip_strings(argv[1], argv[2]);
}
./a.out hello computer
hceolmlpouter

Converting string to one with escape sequences

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.

strcat adds junk to the string

I'm trying to reverse a sentence, without changing the order of words,
For example: "Hello World" => "olleH dlroW"
Here is my code:
#include <stdio.h>
#include <string.h>
char * reverseWords(const char *text);
char * reverseWord(char *word);
int main () {
char *text = "Hello World";
char *result = reverseWords(text);
char *expected_result = "olleH dlroW";
printf("%s == %s\n", result, expected_result);
printf("%d\n", strcmp(result, expected_result));
return 0;
}
char *
reverseWords (const char *text) {
// This function takes a string and reverses it words.
int i, j;
size_t len = strlen(text);
size_t text_size = len * sizeof(char);
// output containst the output or the result
char *output;
// temp_word is a temporary variable,
// it contains each word and it will be
// empty after each space.
char *temp_word;
// temp_char is a temporary variable,
// it contains the current character
// within the for loop below.
char temp_char;
// allocating memory for output.
output = (char *) malloc (text_size + 1);
for(i = 0; i < len; i++) {
// if the text[i] is space, just append it
if (text[i] == ' ') {
output[i] = ' ';
}
// if the text[i] is NULL, just get out of the loop
if (text[i] == '\0') {
break;
}
// allocate memory for the temp_word
temp_word = (char *) malloc (text_size + 1);
// set j to 0, so we can iterate only on the word
j = 0;
// while text[i + j] is not space or NULL, continue the loop
while((text[i + j] != ' ') && (text[i + j] != '\0')) {
// assign and cast test[i+j] to temp_char as a character,
// (it reads it as string by default)
temp_char = (char) text[i+j];
// concat temp_char to the temp_word
strcat(temp_word, &temp_char); // <= PROBLEM
// add one to j
j++;
}
// after the loop, concat the reversed version
// of the word to the output
strcat(output, reverseWord(temp_word));
// if text[i+j] is space, concat space to the output
if (text[i+j] == ' ')
strcat(output, " ");
// free the memory allocated for the temp_word
free(temp_word);
// add j to i, so u can skip
// the character that already read.
i += j;
}
return output;
}
char *
reverseWord (char *word) {
int i, j;
size_t len = strlen(word);
char *output;
output = (char *) malloc (len + 1);
j = 0;
for(i = (len - 1); i >= 0; i--) {
output[j++] = word[i];
}
return output;
}
The problem is the line I marked with <= PROBLEM, On the first word which in this case is "Hello", it does everything just fine.
On the second word which in this case is "World", It adds junky characters to the temp_word,
I checked it with gdb, temp_char doesn't contain the junk, but when strcat runs, the latest character appended to the temp_word would be something like W\006,
It appends \006 to all of the characters within the second word,
The output that I see on the terminal is fine, but printing out strcmp and comparting the result with expected_result returns -94.
What can be the problem?
What's the \006 character?
Why strcat adds it?
How can I prevent this behavior?
strcat() expects addresses of the 1st character of "C"-strings, which in fact are char-arrays with at least one element being equal to '\0'.
Neither the memory temp_word points to nor the memory &temp_char points to meet such requirements.
Due to this the infamous undefined behaviour is invoked, anything can happen from then on.
A possible fix would be to change
temp_word = (char *) malloc (text_size + 1);
to become
temp_word = malloc (text_size + 1); /* Not the issue but the cast is
just useless in C. */
temp_word[0] = '\0';
and this
strcat(temp_word, &temp_char);
to become
strcat(temp_word, (char[2]){temp_char});
There might be other issues with the rest of the code.
The root cause of junk characters is you use wrong input for the 2nd argument of strcat function. see explain below:
At the beginning of your function you declare:
int i, j;
size_t len = strlen(text);
size_t text_size = len * sizeof(char);
// output containst the output or the result
char *output;
// temp_word is a temporary variable,
// it contains each word and it will be
// empty after each space.
char *temp_word;
// temp_char is a temporary variable,
// it contains the current character
// within the for loop below.
char temp_char;
you can print variable's addresses in stack, they will be something like this:
printf("&temp_char=%p,&temp_word=%p,&output=%p,&text_size=%p\n", &temp_char, &temp_word,&output,&text_size);
result:
&temp_char=0x7ffeea172a9f,&temp_word=0x7ffeea172aa0,&output=0x7ffeea172aa8,&text_size=0x7ffeea172ab0
As you can see, &temp_char(0x7ffeea172a9f) is at the bottom of the stack, next 1 byte is &temp_word(0x7ffeea172aa0), next 8 bytes is &output(0x7ffeea172aa8), and so on(I used 64bit OS, so it takes 8 bytes for a pointer)
// concat temp_char to the temp_word
strcat(temp_word, &temp_char); // <= PROBLEM
refer strcat description here: http://www.cplusplus.com/reference/cstring/strcat/
the strcat second argument = &temp_char = 0x7ffeea172a9f. strcat considers that &temp_char(0x7ffeea172a9f) is the starting point of the source string, instead of adding only one char as you expect it will append to temp_word all characters starting from &temp_char(0x7ffeea172a9f) , until it meets terminating null character
The function strcat deals with strings.
In this code snippet
// assign and cast test[i+j] to temp_char as a character,
// (it reads it as string by default)
temp_char = (char) text[i+j];
// concat temp_char to the temp_word
strcat(temp_word, &temp_char); // <= PROBLEM
neither the pointer temp_word nor the pointer &temp_char points to a string.
Moreover array output is not appended with the terminating-zero character for example when the source string consists from blanks.
In any case your approach is too complicated and has many redundant code as for example the condition in the for loop and the condition in the if statement that duplicate each other.
for(i = 0; i < len; i++) {
//…
// if the text[i] is NULL, just get out of the loop
if (text[i] == '\0') {
break;
}
The function can be written simpler as it is shown in the demonstrative program below.
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
char * reverse_words( const char *s )
{
char *result = malloc( strlen( s ) + 1 );
if ( result != NULL )
{
char *p = result;
while ( *s != '\0' )
{
while ( isblank( ( unsigned char )*s ) )
{
*p++ = *s++;
}
const char *q = s;
while ( !isblank( ( unsigned char )*q ) && *q != '\0' ) ++q;
for ( const char *tmp = q; tmp != s; )
{
*p++ = *--tmp;
}
s = q;
}
*p = '\0';
}
return result;
}
int main(void)
{
const char *s = "Hello World";
char *result = reverse_words( s );
puts( s );
puts( result );
free( result );
return 0;
}
The program output is
Hello World
olleH dlroW

Find Every Position of a Given Char Within an Array

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.

Resources