I am a complete beginner.
I have a function which converts an int to an array.
#include <math.h>
#include <stdio.h>
int *convertIntArray(int number) {
int n = log10(number) + 1;
int i;
int *numberArray = calloc(n, sizeof(int));
for (i = 0; i < n; ++i, number /= 10) {
numberArray[i] = number % 10;
}
return numberArray;
}
I'd like to initialise an array named sample in my main function, by passing an integer to the convertIntArray function. My pseudocode looks like:
int main(int argc, char *argv[]) {
int sample = convertIntArray(150);
// rest of main function
But obviously this doesn't work. What is the correct way to do this?
The array is allocated by the converIntArray function and a pointer to its first element is returned. You can store this pointer to array in main if you define array with the appropriate type:
int main(int argc, char *argv[]) {
int *sample = convertIntArray(150);
// rest of main function
Note however that you cannot tell the size of the array pointed to by array from the pointer and the values. You should return either always allocate the maximum size, which is 10 int or return the size some other way, for example as the first element of the array, which you would then allocate with an extra element.
The first thing to note in your code is that you don't include a prototype for function log10() which I guess should be in <math.h>. Or you have done it, but didn't show it in your snippet of code. This is bad posting in StackOverflow, because that leaves us in the dilema of deciding if you made a mistake (by not including it, which will give you undefined behaviour, so, please edit your question, including a minimal, complete and verifiable example.
In case I had to write your function, I should not use log10() because it is a floating point function and you can select the wrong number of digits to allocate in case there's some rounding error in the calculation. Anyway, I'd try to use as less support functions as possible, by changing your interface to this one:
unsigned *number2digits(
unsigned *array_to_work_in, /* the array is provided to the function */
size_t array_size, /* the size of the array, in number of elements */
unsigned source_number, /* the number to be converted */
unsigned base); /* the base to use for conversion */
This approach doesn't force you to include the math library only for the log10() function, and also doesn't make use of the dynamic allocator routines malloc() and calloc(), and the compiler optimises it better if the function doesn't call more external/library functions. In case (see below) you want to use the function on an already allocated array, you don't have to rewrite it. Also, the numbering base is a good thing to pass as parameter, so you are not stuck to base 10 only numbers.
Another error is that you are returning an int * (pointer to int) and you assign the value to a variable of type int (this is a mistake that should have given you a compiler error).
A valid (and complete, and verifiable) example code should be:
#include <stdio.h>
#include <stdlib.h>
unsigned *number2digits(
unsigned *array_to_work_in, /* the array is provided to the function */
size_t array_size, /* the size of the array, in number of elements */
unsigned source_number, /* the number to be converted */
unsigned base) /* the base to use for conversion */
{
size_t i;
for (i = 0; i < array_size; i++) {
array_to_work_in[i] = source_number % base;
source_number /= base;
}
/* if, at this point, source_number != 0, you made an error
* on estimating array size, as the number doesn't fit in
* array_size digits. In case of error, we return NULL to
* indicate the error. */
return source_number == 0 ? array_to_work_in : NULL;
}
#define NUMBER 150000
#define N 10
#define BASE 38
int main()
{
unsigned my_array[N]; /* 10 digits for a base 38 is enough for a 32 bit integer */
unsigned *r = number2digits(my_array, N, NUMBER, BASE);
if (!r) {
fprintf(stderr, "Error, number %u does not fit in %u base %u digits\n",
NUMBER, N, BASE);
exit(EXIT_FAILURE);
}
printf("%u =/base %u/=>", NUMBER, BASE);
int i; /* we use int here as size_t is unsigned and we could
* not detect the loop exit condition */
for (i = N-1; i >= 0; i--) {
printf(" %u", r[i]);
}
printf("\n");
exit(EXIT_SUCCESS);
}
it shows:
$ pru
150000 =/base 38/=> 0 0 0 0 0 0 2 27 33 14
$ _
Related
I'm sorry if my question is quite vague, because it is without context. So I was trying to solve a question: Write a recursive version of the function itoa(i) which converts an integer i into a string.
As I ran out of idea how to solve it, I started looking online to find solutions and I came across some of them which usually use this line: itoa(n/10, s);. For example, from this StackOverflow question: itoa recursively. I can't understand what it does to i.
So I went on and searched for more solutions and I found one that actually works, the program looks like this:
#include <stdio.h>
char *itoa(int n, char s[]);
int main()
{
char number[100];
printf("-90 to string = %s\n", itoa(-90, number));
return 0;
}
char *itoa(int n, char s[])
{
static int i = 0;
if (n < 0) {
s[i++] = '-';
n = -n; /* does not work for largest negative number in two complement */
}
if (n / 10)
itoa(n /10, s);
s[i++] = n % 10 + '0';
s[i] = '\0';
return s;
}
Problem is, according to the solutions I found on other websites, people said that we should avoid using static int i. I did not read why we should do so because I don't know how static works so I don't know if this program is fine or needs improvements.
Your function pretty much almost right, that is for a recursive method. If you were going to parse the digit to string backward, it is right. Otherwise, I just did a couple fix.
For parsing digit to string, the digits that are being parsed are from the right digits to left digits as the remainder is what being used. Thus, when storing those into a string, we will need to go from high to low indexes. If we use remainders for parsing, we will not know the length of the number that is being parsed. Thus, in most parse cases there will be some extra spaces at the beginning of your string or char array.
For using the static i, you can pass a version of it around but it would make it harder to use as you would need to know to always have to pass i at 11. "i" is at 11 because the maximum digits for an int is 10(digits) + 1 sign and the 12th character which not counted by "i" is the null char. To make it easier to use the function, I configured the third parameter to be a void pointer. However, do not pass it an actual pointer, pass it a NULL. When it see NULL as the third parameter, it know that, that is the first call.
#include <stdio.h>
#include <string.h>
char *itoa(int n, char s[], void * );
int main()
{
char number[100] = {0};
printf("-90 to string = %s\n", itoa(154, number, NULL));
printf("-15 to string = %s\n", itoa(-15, number, NULL));
printf("-2147483648 to string = %s\n", itoa(-2147483648, number, NULL));
return 0;
}
// The reason why I pass a void pointer is because
// instead of passing the value is because it easier to use function without needing to know that the string have to go from right left.
// When you first call it just use NULL as the third parameter. Anything else can ruin it.
char *itoa(int n, char s[], void * firstCall )
{
static int i;
if ( firstCall == NULL ) {
i = 11;
s[11] = 0;
}
int neg = 0;
if (n < 0) {
if ( n == -2147483648 ) {
strcpy(s, "-2147483648");
return s;
}
neg=1;
n = -n; /* does not work for largest negative number in two complement */
}
s[--i] = (n % 10) ^ 48;
if ( n / 10 ) itoa(n / 10, s, s);
if ( neg == 1 ) s[--i] = '-';
return &s[i];
}
I have two functions in my main function.
I've tried to accomplish this problem with pointers, but as a beginner, it is very complicated to work with this.
int main(){
int *p;
p = function_A();
function_B(p);
return 0;
}
int function_A(){
static int myArray[3];
myArray[0] = 11;
myArray[1] = 22;
myArray[2] = 33;
return myArray;
}
int function_B(int *myPointer){
// Here I just want to print my array I've got from function_A() to the
// console
printf("%d", *myPointer)
return 0;
}
function_A should return a array and function_B should take this array.
Thanks!
There are some issues your compiler will already have told you.
First, you should define the functions before calling them, or at least forward declare them.
Second, to return an array, you need to return a pointer to the first element of this array, i.e. return type is int * and not int.
Third, as FredK pointed out, when you receive just a pointer, you have no chance to determine how many elements are in the array it points to. You can either terminate the array with a specific value, e.g. 0, or you need to return the size of the array, too.
See the following adaptions made to your program:
int* function_A(int *size){
static int myArray[3];
myArray[0] = 11;
myArray[1] = 22;
myArray[2] = 33;
if (size) {
*size = 3;
}
return myArray;
}
void function_B(int *myPointer, int size){
for (int i=0; i<size; i++) {
printf("%d\n", myPointer[i]);
}
}
int main(){
int *p;
int size=0;
p = function_A(&size);
function_B(p,size);
return 0;
}
Note: a reference to an array degrades to the address of the first byte of the array.
the following proposed code:
cleanly compiles
incorporates the comments to the question
assumes the programmer already knows the size of the array
performs the desired functionality
appended '\n' to format string of calls to printf() so output on separate lines
and now, the proposed code:
#include <stdio.h>
int * function_A( void );
void function_B(int *myPointer);
int main( void )
{
int *p;
p = function_A();
function_B(p);
return 0;
}
int * function_A()
{
static int myArray[3];
myArray[0] = 11;
myArray[1] = 22;
myArray[2] = 33;
return myArray;
}
void function_B(int *myPointer)
{
printf("%d\n", myPointer[0]);
printf("%d\n", myPointer[1]);
printf("%d\n", myPointer[2]);
}
a run of the program produces the following output:
11
22
33
Let's say you have a function that creates an array of ints:
int *create_int_array(const size_t num)
{
int *iarray;
size_t i;
if (num < 1)
return NULL; /* Let's not return an empty array. */
iarray = malloc(num * sizeof iarray[0]);
if (!iarray)
return NULL; /* Out of memory! */
/* Fill in the array with increasing integers. */
for (i = 0; i < num; i++)
iarray[i] = i + 1;
return iarray;
}
Let's say tou have a function that calculates the sum of the integers in the array. If we ignore any overflow issues, it could look like this:
int sum_int_array(const int *iarray, const size_t num)
{
int sum = 0;
size_t i;
/* Sum of an empty array is 0. */
if (num < 1)
return 0;
for (i = 0; i < num; i++)
sum += iarray[i];
return sum;
}
Note that sizeof is not a function, but a C language keyword. Its argument is only examined for its size. Thus, sizeof iarray[0] yields the size of each element in iarray, and is completely safe and valid even if iarray is undefined or NULL at that point. You see that idiom a lot in C programs; learn to read it as "size of first element of iarray", which is the same as "size of each element in iarray", because all C array elements have the exact same size.
In your main(), you could call them thus:
#ifndef NUM
#define NUM 5
#endif
int main(void)
{
int *array, result;
array = create_int_array(NUM);
if (!array) {
fprintf(stderr, "Out of memory!\n");
exit(EXIT_FAILURE);
}
result = sum_int_array(array, NUM);
printf("Sum is %d.\n", result);
free(array);
return EXIT_SUCCESS;
}
As you can see, there is really not much to it. Well, you do need to get familiar with the pointer syntax.
(The rule I like to point out is that when reading pointer types, read the specifiers from right to left, delimited by * read as a pointer to. Thus, int *const a reads as "a is a const, a pointer to int", and const char **b reads as "b is a pointer to a pointer to const char".)
In this kind of situations, a structure describing an array makes much more sense. For example:
typedef struct {
size_t max; /* Maximum number of elements val[] can hold */
size_t num; /* Number of elements in val[] */
int *val;
} iarray;
#define IARRAY_INIT { 0, 0, NULL }
The idea is that you can declare a variable of iarray type just as you would any other variable; but you also initialize those to an empty array using the IARRAY_INIT macro. In other words, thus:
iarray my_array = IARRAY_INIT;
With that initialization, the structure is always initialized to a known state, and we don't need a separate initialization function. We really only need a couple of helper functions:
static inline void iarray_free(iarray *array)
{
if (array) {
free(array->val);
array->max = 0;
array->num = 0;
array->val = NULL;
}
}
/* Try to grow the array dynamically.
Returns the number of elements that can be added right now. */
static inline size_t iarray_need(iarray *array, const size_t more)
{
if (!array)
return 0;
if (array->num + more > array->max) {
size_t max = array->num + more;
void *val;
/* Optional: Growth policy. Instead of allocating exactly
as much memory as needed, we allocate more,
in the hopes that this reduces the number of
realloc() calls, which tend to be a bit slow.
However, we don't want to waste too much
memory by allocating and then not using it. */
if (max < 16) {
/* Always allocate at least 16 elements, */
max = 16;
} else
if (max < 65536) {
/* up to 65535 elements add 50% extra, */
max = (3*max) / 2;
} else {
/* then round up to next multiple of 65536, less 16. */
max = (max | 65535) + 65521;
}
val = realloc(array->val, max * sizeof array->val[0]);
if (!val) {
/* We cannot grow the array. However, the old
array is still intact; realloc() does not
free it if it fails. */
return array->max - array->num;
}
/* Note: the new elements in array->val,
array->val[array->max] to
array->val[max-1], inclusive,
are undefined. That is fine, usually,
but might be important in some special
cases like resizing hash tables or such. */
array->max = max;
array->val = val;
}
return array->max - array->num;
}
/* Optional; same as initializing the variable to IARRAY_INIT. */
static inline void iarray_init(iarray *array)
{
array->max = 0;
array->num = 0;
array->val = NULL;
}
The static inline bit means that the functions are only visible in this compilation unit, and the compiler is free to implement the function directly at the call site. Basically, static inline is used for macro-like functions and accessor functions. If you put the structure in a header file (.h), you'd put the related static inline helper functions in it as well.
The growth policy part is only an example. If you omit the growth policy, and always reallocate to array->num + more elements, your code will call realloc() very often, potentially for every int appended. In most cases, doing it that often will slow down your program, because realloc() (as well as malloc(), calloc()) is kind-of slow. To avoid that, we prefer to pad or round up the allocation a bit: not too much to waste allocated but unused memory, but enough to keep the overall program fast, and not bottlenecked on too many realloc() calls.
A "good growth policy" is very much up to debate, and really depends on the task at hand. The above one should work really well on all current operating systems on desktop machines, laptops, and tablets, when the program needs only one or only a handful of such arrays.
(If a program uses many such arrays, it might implement an iarray_optimize() function, that reallocates the array to exactly the number of elements it has. Whenever an array is unlikely to change size soon, calling that function will ensure not too much memory is sitting unused but allocated in the arrays.)
Let's look at an example function that uses the above. Say, the obvious one: appending an integer to the array:
/* Append an int to the array.
Returns 0 if success, nonzero if an error occurs.
*/
int iarray_append(iarray *array, int value)
{
if (!array)
return -1; /* NULL array specified! */
if (iarray_need(array, 1) < 1)
return -2; /* Not enough memory to grow the array. */
array->val[array->num++] = value;
return 0;
}
Another example function would be one that sorts the ints in an array by ascending or descending value:
static int cmp_int_ascending(const void *ptr1, const void *ptr2)
{
const int val1 = *(const int *)ptr1;
const int val2 = *(const int *)ptr2;
return (val1 < val2) ? -1 :
(val1 > val2) ? +1 : 0;
}
static int cmp_int_descending(const void *ptr1, const void *ptr2)
{
const int val1 = *(const int *)ptr1;
const int val2 = *(const int *)ptr2;
return (val1 < val2) ? +1 :
(val1 > val2) ? -1 : 0;
}
static void iarray_sort(iarray *array, int direction)
{
if (array && array->num > 1) {
if (direction > 0)
qsort(array->val, array->num, sizeof array->val[0],
cmp_int_ascending);
else
if (direction < 0)
qsort(array->val, array->num, sizeof array->val[0],
cmp_int_descending);
}
}
Many new programmers do not realize that the standard C library has that nifty and quite efficient qsort() function for sorting arrays; all it needs is a comparison function. If the direction is positive for iarray_sort(), the array is sorted in ascending order, smallest int first; if direction is negative, then in descending order, largest int first.
A simple example main() that reads in all valid ints from standard input, sorts them, and prints them in ascending order (increasing value):
int main(void)
{
iarray array = IARRAY_INIT;
int value;
size_t i;
while (scanf(" %d", &value) == 1)
if (iarray_append(&array, value)) {
fprintf(stderr, "Out of memory.\n");
exit(EXIT_FAILURE);
}
iarray_sort(&array, +1); /* sort by increasing value */
for (i = 0; i < array.num; i++)
printf("%d\n", array.val[i]);
iarray_free(&array);
return EXIT_SUCCESS;
}
If size of array is indeed 3 (or other small fixed value), then you can simply use structs as values, something like:
struct ints3 {
int values[3];
// if needed, can add other fields
}
int main(){
struct ints3 ints;
ints = function_A();
function_B(&ints);
return 0;
}
// note about function_A signature: void is important,
// because in C empty () means function can take any arguments...
struct ints3 function_A(void) {
// use C designated initialiser syntax to create struct value,
// and return it directly
return (struct ints3){ .values = { 11, 22, 33 } };
}
int function_B(const struct ints3 *ints) {
// pass struct as const pointer to avoid copy,
// though difference to just passing a value in this case is insignificant
// could use for loop, see other answers, but it's just 3 values, so:
printf("%d %d %d\n", ints->values[0], ints->values[1], ints->values[2]);
return 0; // does this function really need return value?
}
I'm tasked with writing a function that will identify all the even numbers in an sample array {10,2,9,3,1,98,8] and place them in an array called EvenNumbers. I have to allow the function so that it works with different combinations of numbers in the array not just the numbers in the sample array above.
I'm wondering is there any way to add numbers to an array that could be different every time? How would I extract the even numbers an place them into an array? Also
for the even array size its giving me an error that the expression must have a constant value but when I use const int it still gives me that error.
Here is the full question.
"Using the array of sample values {10,2,9,3,1,98,8}, write a function that will identify all the even numbers in an array and place it in an array called EvenNumbers. The function must work in all cases, not just in the case of the array shown. Assume that the array size is always available through a global constant called MAX"
Here is what I have so far. I've no idea how I will extract the even numbers from a for loop and place them in an array. I also dont know what the "expression must have a constant value" is about?
#include <stdio.h>
#include <stdlib.h>
void EvenNumber(int Array[], int size);
int main()
{
int array[7] = { 10,2,9,3,1,98,8 };
EvenNumber(array, 7);
}
void EvenNumber(int Array[], int size)
{
int i;
int EvenArraySize;
for (i = 0; i < size; i++)
{
if (Array[i] % 2 == 0)
{
EvenArraySize++;
}
}
int Even[EvenArraySize];
}
The right way to go is to use malloc to allocate just the right amount of memory.
Count the number of even numbers
Allocate the space needed to store them
Copy even numbers in this space
Do whatever you want with these numbers
Free the allocated space
Snippet:
#include <stdio.h>
#include <stdlib.h>
#define MAX 7
int
main()
{
int array[] = {10,2,9,3,1,98,8};
int *even_numbers;
int i, nb_even_numbers;
for (i = 0, nb_even_numbers = 0; i < MAX; i++)
{
if (array[i] % 2 == 0)
nb_even_numbers++;
}
even_numbers = malloc(sizeof(int) * nb_even_numbers);
if (!even_numbers)
{
perror("malloc");
return 1;
}
for (i = 0, nb_even_numbers = 0; i < MAX; i++)
{
if (array[i] % 2 == 0)
even_numbers[nb_even_numbers++] = array[i];
}
/* do your stuff here */
free(even_numbers);
return 0;
}
First, you can never return a statically declared array from a function (even though you don't explicitly try, your Even array is destroyed when EvenNumber returns) Why? The function stack frame for EvenNumber is released for reuse on return and any locally declared arrays are no longer valid.
You either need to pass a second array as a parameter to EvenNumber, or you can dynamically allocate storage for Even in EvenNumber (with, e.g. malloc or calloc or realloc) and return a pointer to the beginning of the array. (you must also have some way to return the size or use a constant for a max size).
There is no need to use % (modulo) to test whether a number is odd/even. All you need to do is look at bit-0 (little endian). If it is 0, then the number is odd, if it is 1, then its even. Much more efficient than calling modulo which incorporates division.
Finally, main is type int and therefore returns a value.
Putting those pieces together, you can do something simple like the following:
#include <stdio.h>
#include <stdlib.h>
void EvenNumber (int *array, int *even, int size, int *esize);
int main (void)
{
int array[] = { 10,2,9,3,1,98,8 },
i, n = sizeof array / sizeof *array,
even[n], /* a VLA of the same size as array is fine here */
esize = 0;
EvenNumber (array, even, n, &esize);
printf ("array: ");
for (i = 0; i < n; i++)
printf (" %2d", array[i]);
printf ("\neven : ");
for (i = 0; i < esize; i++)
printf (" %2d", even[i]);
putchar ('\n');
return 0;
}
void EvenNumber (int *array, int *even, int size, int *esize)
{
int i;
for (i = 0; i < size; i++)
if ((array[i] & 1) == 0) /* simply looking at bit-0 is all you need */
even[(*esize)++] = array[i];
}
Note: esize is passed as a pointer to EvenNumber and updated within the function so that the number of elements in even are available back in the calling function (main() here).
Example Use/Output
$ ./bin/arrayeven
array: 10 2 9 3 1 98 8
even : 10 2 98 8
Let me know if you have any further questions.
Sorry for my question, I know there are a lot similars but I didn't found any that is simple enaugh to help me.
I've started coding in C and try to solve a simple exercise: Read an integers array from command line, sum the elements using the function array_sum and print result. (input example array of 3 elements: 3 0 1 2)
int array_sum(int *array, size_t size);
int main(int argc, char **argv){
int sum=array_sum(argv, argc);
printf("array_sum: %i\n", sum);
return 0;
}
my problem is that argv is a char array and the function want an integer array.
Should I convert elements one by one in a new int array? There are better ways?
argv is an array of pointers to C strings. You need to convert the strings into integers first. You can do something like this:
int array_sum(int *array, size_t size);
int main(int argc, char **argv){
int *num_arr = malloc((argc - 1) * sizeof *num_arr);
for (int i = 0; i < argc - 1; ++i)
num_arr[i] = atoi(argv[i+1]);
int sum = array_sum(num_arr, argc - 1);
printf("array_sum: %i\n", sum);
free(num_arr);
return 0;
}
The only way to make the code in main shorter is by moving the conversion loop into a separate function that returns the malloced pointer.
In your code, char *argv[] is an array of char* pointers supplied from the command line. In order to convert the numbers supplied, you can use the following:
atoi(), which converts string arguement to an integer type.
Or strtol(), which converts the initial part of a string to a long int, given a base.
Other special functions from C99, alot of which are described in this post.
Since atoi() has no error checking, it is best to use strtol(), which allows extensive error checking.
You should store these converted numbers in a dynamically allocated int* pointer, which will need to be allocated on the heap using malloc(), which was suggested by #StoryTeller in his answer. You could also just declare an array on the stack, such as int arr[n]. The problem arises when you want to return this array in a function, which is not possible. Using a pointer in this case would allow more flexibility for abstraction.
malloc()allocates block of memory on the heap, and returns a void* pointer to it.
Note: malloc() should always be checked, as it can return NULL. You need to also free() this pointer at the end.
Here is some example code:
#include <stdio.h>
#include <stdlib.h>
#define BASE 10
/* Guessed that your function would look like this */
int array_sum(int *array, size_t size) {
int sum = 0;
for (size_t i = 0; i < size; i++) {
sum += array[i];
}
return sum;
}
int main(int argc, char *argv[]) {
int *arr = NULL;
char *endptr = NULL;
int check, sum;
size_t ndigits = (size_t)argc-1;
/* allocate pointer */
arr = malloc(ndigits * sizeof *arr);
if (arr == NULL) {
fprintf(stderr, "Cannot %zu spaces for integers\n", ndigits);
exit(EXIT_FAILURE);
}
for (size_t i = 0; i < ndigits; i++) {
/* sufficient checking for strtol(), more can possibly be added here */
check = strtol(argv[i+1], &endptr, BASE);
if (endptr != argv[i+1] && *endptr == '\0') {
arr[i] = check;
}
}
sum = array_sum(arr, ndigits);
printf("array_sum: %d\n", sum);
/* pointer is free'd */
free(arr);
arr = NULL;
return 0;
}
Example input:
$ gcc -Wall -Wextra -std=c99 -o sumcommands sumcommmands.c
$ ./sumcommands 3 2 1
Output:
array_sum: 6
Note: You can use more error checking for strtol() on the Man page.
Why do you need to pass an int array as argument to the function ? No need to create an extra int array when you can simply do this :
int array_sum(char **argv, int argc){
int sum = 0;
for(int i = 0;i < argc - 1;i++){
sum += atoi(argv[i])
}
return sum;
}
You can use atoi() function to convert char ** array to **int . what i see here is each integer you type is converting into string rather than char.
trying to convert dec to 32-base, and then print it to a file.
const char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
char* baseConverter(int num, int base)
{ char* res;
int i=0;
if (num == 0 || base == 10)
{
snprintf(res,"%03x",num);
return *res;
}
while( num > 0 )
{
*(res+i) = digits[num%base];
num=num/base;
}
return *res;
}
and then at the output code :
sprintf(line, "%03s", baseConverter(i, 32);
but I keep getting that Segmentation fault (core dumped) error at running.
There are several things going on here:
First an uninitialised local pointer has an indeterminate value; it doesn't point anywhere in particular. The NULL pointer doesn't point anywhere either, but at least you can test for a NULL pointer easily. Make a habit of initalising a pointer to make it point to valid memory or to make it explicitly null.
The pointer is supposed to point to a char buffer. The way your function looks like, you must allocate memory for that buffer on the heap with malloc. (You can't use local storage, because that would be invalidated immediately.)
Don't make base 10 a special case. (You're even doing it wrong by printing base 10 numbers as hex.)
Your method of printing is okay, but you print the number backwards. So determine the required klength first and then decrement the position you print at.
Here, you deal with the raw characters. Use res[i] rather than do complicated things with the standard library functions. In particular, don't build strings by concatenating or printing strings to themselves. That's very likely undefined behaviour.
A possible implementation of your function could look like:
int ndigits(int num, int base)
{
int n = 0;
while (num) {
n++;
num /= base;
}
if (n == 0) n++;
return n;
}
char* baseConverter(int num, int base)
{
if (num >= 0 && base > 1 && base <= 36) {
int n = ndigits(num, base);
char *res = malloc(n + 1);
int i = n;
res[n] = '\0';
if (num == 0) res[--i] = '0';
while (num) {
res[--i] = digits[num % base];
num /= base;
}
return res;
}
return NULL;
}
Note how an auxiliary function is used to determine the length of the string. The string is then filled backwards, staring with the null terminator. Also note how invalid cases are handled by returning NULL.
Your calling code must explicitly free the string after using it:
int n = rand() % 100000 + 1;
int m = rand() % 10 + 2;
char *p = baseConverter(n, m);
if (p) printf("%d#%d == %s\n", n, m, p);
free(p);
C has manual memory management and keeping track of allocated stuff is tedious. You can't, for example, call baseConverter from inside printf, because you'd lose the handle to the allocated string.
Another popular variant is to have the calling code allocate the memory and then pas a buffer and its size to the function to fill it. A prototype could then look like this:
void sbase(char buf, size_t buflen, int num, int base);
It would then be called like this:
char buf[33]; // Maximum, when base 2 is printed
sbase(buf, sizeof(buf), 5000, 13);
puts(buf);
Because buf is an automatic variable, no freeing is to be done. (How to implement thins and how to properly enforce that the buffer size isn't exceeded is left as an exercise. :))
The main errors have already been pointed out.
Here is another suggested routine (it doesn't require malloc)
The function sets the value of a pointer to the number of converted digits, to make it easy to print out the required digits.
#include <stdio.h>
/* function takes pointer to array, size of array + number/base
and pointer for number of digits in conversion */
void make32(int *res32, int len, int num, int base, int *rln);
int main()
{
int digits32[20]; // size according to max conversion number in base 32
int len32 = sizeof(digits32)/sizeof(digits32[0]);
int in32, resln, n;
/* convert this number */
in32 = 10000;
/* call function with pointer + size & number/base & ptr to # converted digits*/
make32(digits32, len32, in32, 32, &resln);
/* print out result - reverse order - use number of digits */
for(n = resln; n >= 0; n--) {
printf("%d ", digits32[n]);
}
printf("\n");
return (0);
}
void make32(int *res32, int len, int num, int base, int *rln)
{
int i = 0;
while( num > 0 && i <= len ) {
res32[i] = num % base;
num = num / base;
i++;
}
/* set the number of converted digits */
*rln = i - 1;
}