Global variable losing data in C? - c

I am trying to create a array of array of string where each row (if considered matrix) should have 3 strings of any length and a maximum of 10 rows
The data Structure is correct but I am very much surprised with the output I get in the global variable. So the matrix would act as the database to the program and hence kept in global space
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
// Maximum buffer size needed
#define MAX_NUM_ITEMS 10
#define MAX_ITEM_PER_ROW 3
static char *array[MAX_NUM_ITEMS][MAX_ITEM_PER_ROW];
#define ITOA_BASE_N (sizeof(unsigned)*CHAR_BIT + 1)
char *itoa_base(char *, int , int);
#define TO_BASE(x,b) itoa_base((char [ITOA_BASE_N]){0} , (x), (b))
char *itoa_base(char *s, int x, int base) {
s += ITOA_BASE_N - 1;
*s = '\0';
if (base >= 2 && base <= 36) {
int x0 = x;
do {
*(--s) = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[abs(x % base)];
x /= base;
} while (x);
if (x0 < 0) {
*(--s) = '-';
}
}
return s;
}
int main(void)
{
int count = 0;
for (int i = 0; i < MAX_NUM_ITEMS; i++){
for (int j = 0; j < MAX_ITEM_PER_ROW; j++ ){
++count;
array[i][j] = TO_BASE(count, 16);
}
}
for (int i = 0; i < MAX_NUM_ITEMS; i++){
for (int j = 0; j < MAX_ITEM_PER_ROW; j++ ){
printf("%s ",array[i][j]);
}
printf("\n");
}
return 0;
}
From my logic I should see
1 2 3
4 5 6
7 8 9 and so on and not E E E
can't understand why that is happening

First, this:
(char [ITOA_BASE_N]){0}
Does not get you a new instance of a character array, unlike say golang. So, every time you call itoa(), you are calling it with the same character array. Somewhat worse, the character array is occupying a reclaimable stack address [ its scope is only that inner loop ], so it can be over written with random stuff shortly after. It is remarkably consistent though; I will give it that.
Changing the invocation to:
array[i][j] = strdup(TO_BASE(count, 16));
and adding a #include at the top produces the output you wanted.
If dynamic allocation is not permissible in your application, you will have to use a static allocation scheme, which you could make a bounded version of strdup like:
char *strnew(char *s) {
static char strspace[ITOA_BASE_N * MAX_NUM_ITEMS * MAX_ITEM_PER_ROW ];
static char *strnext = strspace;
if (strlen(s) + strspace >= &strspace[sizeof strspace]) {
s = "<error: out of space>"; /* something more clever is possible */
} else {
strcpy(strnext, s);
s = strnext;
strnext += strlen(strnext)+1;
}
return s;
}
which you could substitute for strdup. If you do the next person down the line a favour and use a more descriptive notion like MAX_STRING_SPACE which is based on the calculation; and rather than insert a "bad value", cause some sort of exception, I am sure they would appreciate it.

The problem is here:
itoa_base((char [ITOA_BASE_N]){0} , (x), (b))
^^^^^^^^^^^^^^^^^^^^^^^
you are allocating a temp array (on the stack) which is only valid up to the end of the containing expression statement. So when the time comes to print them, the pointers you've stored in the matrix are dangling. What the compiler ends up doing is reusing the same memory for every call, so the strings end up overwriting.
You could instead use a static matrix of arrays rather than pointers:
static char array[MAX_NUM_ITEMS][MAX_ITEM_PER_ROW][ITOA_BASE_N];
then your call in the first loop becomes
itoa_base(array[i][j], count, 16);
you'll also need to "fix" itoa_base so it puts the result in the front of the array rather than the back. Obvious way is with a recursive loop like:
char *itoa_base(char *s, int x, int base) {
if (base >= 2 && base <= 36) {
if (x < 0) {
*s++ = '-';
x = -x; }
if (x >= base)
s = itoa_base(s, x/base, base);
*s++ = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[x % base];
}
*s = '\0';
return s;
}

Related

How to sort dates from an array in c

I'm trying to sort dates from an array i've got the following code (without including the array and the file that i'm trying to read and the other with the sorted dates that i'm trying to write.
int aniomayor=tot[0].anio;
int diamayor=tot[0].dia;
int mesmayor=tot[0].mes;
while (i<nf) {
if (tot[i].anio > aniomayor) {
int aniomayor=tot[i].anio;
int diamayor=tot[i].dia;
int mesmayor=tot[i].mes;
}
else if (tot[i].anio == aniomayor && tot[i].mes > mesmayor) {
int aniomayor=tot[i].anio;
int diamayor=tot[i].dia;
int mesmayor=tot[i].mes;
}
else if (tot[i].anio == aniomayor && tot[i].mes == mesmayor && tot[i].dia > diamayor) {
int aniomayor=tot[i].anio;
int diamayor=tot[i].dia;
int mesmayor=tot[i].mes;
}
i++;
}
fprintf(f, "%s ", diamayor);
fprintf(f, "%s ", mesmayor);
fprintf(f, "%s \n", aniomayor);
I think it would work but in the 2,3,4.. line it will print always the same date and i don't know how to do for it to ignore the dates that already had been sorted. Thanks in advance.
The original int declaration establishes variables. The subsequent ones create "shadow" variables that have the same name but are not the same variable.
Here's a demonstration:
#include <stdio.h>
int main() {
int x = 1;
if (x == 1) {
int x = 2;
printf("x=%d\n", x);
}
printf("x=%d\n", x);
return 0;
}
This prints:
x=2
x=1
The top-level x never gets modified, so it appears to revert to the original value.
You should remove the int prefix from those, just assign to the existing variable.
When you say int x = y; in C you are declaring a variable and assigning a value. To assign to an existing variable x = y; is sufficient.
The int prefix is only necessary on the first instance of the variable so the compiler knows what type to use for that and all subsequent references inside the same scope.
Now normally the compiler would complain about creating another variable with the same name if it's done in the same scope. In your case because you're doing it inside an if, technically that's a different scope so you can have duplicates.
As has been mentioned in the comments, it is preferable to use qsort, (if one doesn't care about stability.) One needs a function pointer, which is compare_dates in the code below.
#include <stdlib.h> /* EXIT*, rand, qsort */
#include <stdio.h> /* *printf */
#include <time.h> /* clock */
#include <assert.h> /* assert */
struct Date { int anio, mes, dia; };
/** Random [i, j]. https://stackoverflow.com/a/6852396/2472827
This is just used for test purposes. */
static int rand_range(const int i, const int j) {
const unsigned long max = (unsigned long)j - i,
num_bins = max + 1l,
num_rand = (unsigned long)RAND_MAX + 1,
bin_size = num_rand / num_bins,
defect = num_rand % num_bins;
unsigned long x;
assert(i <= j && num_bins <= RAND_MAX);
do { x = 1l * rand(); } while (num_rand - defect <= x);
return i + x / bin_size;
}
/** Initiaises the date with random. */
static void init_date(struct Date *const date) {
assert(date);
date->anio = rand_range(1950, 2050);
date->mes = rand_range(1, 12);
date->dia = rand_range(1, 30); /* Approximately. */
}
/** Prints the date in a static string.
Assumes the date is sanitised, or else this presents a risk of overflow. */
static const char *print_date(const struct Date *const date) {
static char print[128]; /* Should be 11 if -999 <= year < 9999. */
assert(date);
sprintf(print, "%4.4d-%2.2d-%2.2d", date->anio, date->mes, date->dia);
return print;
}
/** The arguments must be const struct Date *.
#return -, =, + */
static int compare_dates(const void *p, const void *q) {
const struct Date *x = (const struct Date *)p, *y = (const struct Date *)q;
assert(p && q);
if(x->anio > y->anio) return 1;
if(x->anio < y->anio) return -1;
if(x->mes > y->mes) return 1;
if(x->mes < y->mes) return -1;
if(x->dia > y->dia) return 1;
if(x->dia < y->dia) return -1;
return 0;
}
int main(void) {
struct Date dates[64];
const size_t dates_size = sizeof dates / sizeof *dates;
size_t i;
/* Generate dates. */
srand((unsigned)clock());
for(i = 0; i < dates_size; i++) init_date(dates + i);
/* Sort it using compare_dates. */
qsort(dates, dates_size, sizeof *dates, &compare_dates);
/* Print. */
for(i = 0; i < dates_size; i++) printf("%s.\n", print_date(dates + i));
return EXIT_SUCCESS;
}
See How to generate a random integer number from within a range.

Requiring help to understand arrays

I'm learning about arrays in C and I can't figure out why the following is not correct?
#include <cs50.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
int main(void)
{
string plaintext = get_string();
int x = 5;
long long N = strlen(plaintext);
string a = plaintext;
long long c = 0;
int z = x;
for(int i = 0; i < N + (N/x) ; i++)
{
if( i == x)
{
a[c] = 32;
c++;
z = (z + x);
//printf("%c\n", a[c]);
}
a[c] = plaintext[i];
//printf("%c\n", a[c]);
c++;
}
printf("%s\n", a);
}
It's meant to insert spaces into a string of text after every x chars... I know it's not efficient (I reckon I need something called pointers) but why isn't it working? I went through it using a debugger and it seems like my original string is changing as I go... but why?
Assuming string is char * then text and a point to the same string. That explains why your original string changes. What you can do is:
string a= malloc(N+1 + N/x +1);
This allocates space for a new string, into which you copy the original with a space after every x characters. Add 1 for the terminating null character and 1 "to be safe" when x or N are odd.
#include <bits/stdc++.h>
using namespace std;
#define freinput "input.txt","r",stdin
#define freoutput "output.txt","w",stdout
#define mp make_pair
#define fi first
#define sc second
#define ellapse printf("Time : %0.3lf\n",clock()*1.0/CLOCKS_PER_SEC);
typedef long long ll;
typedef unsigned long int uld;
typedef vector<int> vi;
typedef vector<string> vs;
typedef pair<int,int> pii;
string s;
string stringInsertion(int x,string neww){
for(int i = 0;i<s.size();i++){
if(i!=0 && i%x==0){
neww=neww+' '+s[i];
}
else neww+=s[i];
}
return neww;
}
int main(){
cin>>s;
int x = 2;
string neww="";
cout<<stringInsertion(x,neww);
}
just set the x number.hope this help
Okay, let's do something similar first: Print out the string with spaces. Use i to loop through the string. Every time i is evenly divisibly by x, we print a space before we print the character, but not at the beginning:
void print_spaced(const char *s, int x)
{
int i;
for (i = 0; s[i]; i++) {
if (i && i % x == 0) putchar(' ');
putchar(s[i]);
}
putchar('\n');
}
You don't need to determine the length beforehand, because you can stop when you hit the terminating null character. That is, keep going as long as s[i] is not null. (Recall that s[i] is the same as s[i] != '\0' and similarly, i is the same as i != 0.)
Now let's fill a char array with the spaced out string instead of printing it:
int space_out_unsafe(char *res, const char *s, int x)
{
int i, k = 0;
for (i = 0; s[i]; i++) {
if (i && i % x == 0) res[k++] = ' ';
res[k++] = s[i];
}
res[k] = '\0';
return k;
}
This function takes an additional parameter: A char buffer to fill. It has a second index, k, which is the current length of the result buffer. Whenever we printed in the first version, we now append a character to the string:
res[k++] = '#';
Tis overwrites the current end and moves k on one position. We don't write a newline at the end, but we must null-terminate the result.
There is one problem, though: The buffer may overflow; note how I have labelled the function above unsafe. Arrays in C have a fixed size and won't grow automatically when something is appended. It is there fore a good idea to pass the maximum buffer size max to the function and check for overflow before appending:
int space_out(char *res, int max, const char *s, int x)
{
int i, k = 0;
for (i = 0; s[i]; i++) {
if (i && i % x == 0 && k < max - 1) res[k++] = ' ';
if (k < max - 1) res[k++] = s[i];
}
res[k] = '\0';
return k;
}
You can now use this function like this:
char res[20];
space_out(res, sizeof(res), "Doremifasola", 2);
puts(res);
There are other ways to accomplish this. You could allocate the memory dynamically, as Paul suggested. That way, you can cater for the additional space you need, but you also make the caller of the function take care of cleaning up the allocated memory with free. Dynamically allocating memory is something to look into after your first week. :)
Another possibility is to space out the string in place, that modify the contents of the original buffer. You still have to take care to provide the extra space, though. (Usually, in-place midofication is used when the result string is shorter, e.g. when filtering out characters.) You should also process your string from the and as not to overwrite data you need later with spaces. If you feel confident, that's an exercise for next week, too.

Need to convert int to string using C

Hi I am pretty new to coding and I really need help.
Basically I have a decimal value and I converted it to a binary value.
Using this method
long decimalToBinary(long n)
{
int remainder;
long binary = 0, i = 1;
while(n != 0)
{
remainder = n%2;
n = n/2;
binary= binary + (remainder*i);
i = i*10;
}
return binary;
}
And I want to give each character of the binary into it's own space inside an array. However, I can't seem to save digits from the return values in my string array. I think it has something to do with converting the long to string but I could be wrong! Here is what I have so far.
I do not want to use sprintf(); I do not wish to print the value I just want the value stored inside it so that the if conditions can read it. Any help would be appreciated!
int decimalG = 24;
long binaryG = decimalToBinary(decimalG);
char myStringG[8] = {binaryG};
for( int i = 0; i<8; i++)
{
if (myStringG[i] == '1' )
{
T1();
}
else
{
T0();
}
}
In this case since the decimal is 24, the binary would be 11000 therefore it should execute the the function T1(); 2 times and T0() 6 times. But it doesn't do that and I can't seem to find the answer to store the saved values in the array.
*Ps the Itoa(); function is also not an option. Thanks in Advance! :)
As the post is tagged arm using malloc() might not be the best approach, although the simplest. If you insist on using arrays:
#include <stdio.h>
#include <stdlib.h>
int decimalToBinary(long n, char out[], int len)
{
long remainder;
// C arrays are zero based
len--;
// TODO: check if the input is reasonable
while (n != 0) {
// pick a bit
remainder = n % 2;
// shift n one bit to the right
// It is the same as n = n/2 but
// is more telling of what you are doing:
// shifting the whole thing to the right
// and drop the least significant bit
n >>= 1;
// Check boundaries! Always!
if (len < 0) {
// return zero for "Fail"
return 0;
}
// doing the following four things at once:
// cast remainder to char
// add the numerical value of the digit "0"
// put it into the array at place len
// decrement len
out[len--] = (char) remainder + '0';
}
// return non-zero value for "All OK"
return 1;
}
// I don't know what you do here, but it
// doesn't matter at all for this example
void T0()
{
fputc('0', stdout);
}
void T1()
{
fputc('1', stdout);
}
int main()
{
// your input
int decimalG = 24;
// an array able to hold 8 (eight) elements of type char
char myStringG[8];
// call decimalToBinary with the number, the array and
// the length of that array
if (!decimalToBinary(decimalG, myStringG, 8)) {
fprintf(stderr, "decimalToBinary failed\n");
exit(EXIT_FAILURE);
}
// Print the whole array
// How to get rid of the leading zeros is left to you
for (int i = 0; i < 8; i++) {
if (myStringG[i] == '1') {
T1();
} else {
T0();
}
}
// just for the optics
fputc('\n', stdout);
exit(EXIT_SUCCESS);
}
Computing the length needed is tricky, but if you know the size of long your Micro uses (8, 16, 32, or even 64 bit these days) you can take that as the maximum size for the array. Leaves the leading zeros but that should not be a problem, or is it?
To achieve your goal, you don't have to convert a decimal value to binary:
unsigned decimalG = 24; // Assumed positive, for negative values
// have implementation-defined representation
for (; decimalG; decimalG >>= 1) {
if(decimalG & 1) {
// Do something
} else {
// Do something else
}
}
Or you can use a union, but I'm not sure whether this approach is well defined by the standard.
If you stick to writing decimalToBinary, note that you'll have to use an array:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
char *decimalToBinary(unsigned n);
int
main(void) {
int decimalG = 15;
char *binary = decimalToBinary(decimalG);
puts(binary);
free(binary);
}
char *
decimalToBinary(unsigned n) {
// Don't forget to free() it after use!!!
char *binary = malloc(sizeof(unsigned) * CHAR_BIT + 1);
if(!binary) return 0;
size_t i;
for (i = 0; i < sizeof(unsigned) * CHAR_BIT; i++) {
binary[i] = '0' + ((n >> i) & 1); // in reverse order
}
binary[i] = 0;
return binary;
}
Use the itoa (integer-to-ascii) function.
http://www.cplusplus.com/reference/cstdlib/itoa/
EDIT: Correction:
Don't be an idiot, use the itoa (integer-to-ascii) function.
http://www.cplusplus.com/reference/cstdlib/itoa/
EDIT:
Maybe I wasn't clear enough. I saw the line that said:
*Ps the Itoa(); function is also not an option.
This is completely unreasonable. You want to reinvent the wheel, but you want someone else to do it? What do you possibly have against itoa? It's part of the standard. It will always exist, no matter what platform you're targeting or version of C that you're using.
I want to give each character of the binary into it's own
space inside an array. However, I can't seem to save digits
from the return values in my string array.
There are a number of ways to approach this, if I understand what you are asking. First, there is no need to actually store the results of the binary representation of your number in an array to call T1() or T0() based on the bit value of any given bit that makes up the number.
Take your example 24 (binary 11000). If I read your post correctly you state:
In this case since the decimal is 24, the binary
would be 11000 therefore it should execute the the
function T1() 2 times and T0() 6 times.
(I'm not sure where you get 6 times, it looks like you intended that T0() would be called 3 times)
If you have T0 and T1 defined, for example, to simply let you know when they are called, e.g.:
void T1 (void) { puts ("T1 called"); }
void T0 (void) { puts ("T0 called"); }
You can write a function (say named callt) to call T1 for each 1-bit and T0 for each 0-bit in a number simply as follows:
void callt (const unsigned long v)
{
if (!v) { putchar ('0'); return; };
size_t sz = sizeof v * CHAR_BIT;
unsigned long rem = 0;
while (sz--)
if ((rem = v >> sz)) {
if (rem & 1)
T1();
else
T0();
}
}
So far example if you passed 24 to the function callt (24), the output would be:
$ ./bin/dec2bincallt
T1 called
T1 called
T0 called
T0 called
T0 called
(full example provided at the end of answer)
On the other hand, if you really do want to give each character of the binary into it's own space inside an array, then you would simply need to pass an array to capture the bit values (either the ASCII character representations for '0' and '1', or just 0 and 1) instead of calling T0 and T1 (you would also add a few lines to handle v=0 and also the nul-terminating character if you will use the array as a string) For example:
/** copy 'sz' bits of the binary representation of 'v' to 's'.
* returns pointer to 's', on success, empty string otherwise.
* 's' must be adequately sized to hold 'sz + 1' bytes.
*/
char *bincpy (char *s, unsigned long v, unsigned sz)
{
if (!s || !sz) {
*s = 0;
return s;
}
if (!v) {
*s = '0';
*(s + 1) = 0;
return s;
}
unsigned i;
for (i = 0; i < sz; i++)
s[i] = (v >> (sz - 1 - i)) & 1 ? '1' : '0';
s[sz] = 0;
return s;
}
Let me know if you have any additional questions. Below are two example programs. Both take as their first argument the number to convert (or to process) as binary (default: 24 if no argument is given). The first simply calls T1 for each 1-bit and T0 for each 0-bit:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h> /* for CHAR_BIT */
void callt (const unsigned long v);
void T1 (void) { puts ("T1 called"); }
void T0 (void) { puts ("T0 called"); }
int main (int argc, char **argv) {
unsigned long v = argc > 1 ? strtoul (argv[1], NULL, 10) : 24;
callt (v);
return 0;
}
void callt (const unsigned long v)
{
if (!v) { putchar ('0'); return; };
size_t sz = sizeof v * CHAR_BIT;
unsigned long rem = 0;
while (sz--)
if ((rem = v >> sz)) {
if (rem & 1) T1(); else T0();
}
}
Example Use/Output
$ ./bin/dec2bincallt
T1 called
T1 called
T0 called
T0 called
T0 called
$ ./bin/dec2bincallt 11
T1 called
T0 called
T1 called
T1 called
The second stores each bit of the binary representation for the value as a nul-terminated string and prints the result:
#include <stdio.h>
#include <stdlib.h>
#define BITS_PER_LONG 64 /* define as needed */
char *bincpy (char *s, unsigned long v, unsigned sz);
int main (int argc, char **argv) {
unsigned long v = argc > 1 ? strtoul (argv[1], NULL, 10) : 24;
char array[BITS_PER_LONG + 1] = "";
printf (" values in array: %s\n", bincpy (array, v, 16));
return 0;
}
/** copy 'sz' bits of the binary representation of 'v' to 's'.
* returns pointer to 's', on success, empty string otherwise.
* 's' must be adequately sized to hold 'sz + 1' bytes.
*/
char *bincpy (char *s, unsigned long v, unsigned sz)
{
if (!s || !sz) {
*s = 0;
return s;
}
if (!v) {
*s = '0';
*(s + 1) = 0;
return s;
}
unsigned i;
for (i = 0; i < sz; i++)
s[i] = (v >> (sz - 1 - i)) & 1 ? '1' : '0';
s[sz] = 0;
return s;
}
Example Use/Output
(padding to 16 bits)
$ ./bin/dec2binarray
values in array: 0000000000011000
$ ./bin/dec2binarray 11
values in array: 0000000000001011

Segmentation fault at base converting in C

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;
}

Declaring a 2-dimensional array of unknown size, C

I have an array declared as a member of a struct in C. The array is declared as:
char mValue[MAXROWS][MAXCOLUMNS];
where MAXROWS and MAXROWS are 300. Is there a better way to do this? I mean, should I declare these as pointers instead?
Thanks!
As the previous poster suggested, a good way is to create a linear array and then "convert it to 2D". Many times, caching the 2D pointers greatly increases the speed of programs that use this array, like so:
mystruct *p = (mystruct*)calloc(ROWS * COLUMNS, sizeof(mystruct));
mystruct **p2 = (mystruct**)calloc(ROWS, sizeof(mystruct*));
for (int i = 0; i < ROWS; i++)
p2[i] = p + i*COLUMNS;
Then, you can simply access a 2D element with:
p2[row][column] = foo;
If all your rows are the same size, you should use a 1D array with the rows stored in sequence:
ABCDE
FGHIJ ---> ABCDEFGHIJKLMNO
KLMNO
The element at row i, column j will be at index i * ROW_LENGTH + j in the 1D array.
You can allocate the array using malloc(ROW_LENGTH * NUM_ROWS).
Another technique is to create a linear array and then convert it to 2d:
char *p = malloc(ROWS * COLUMNS);
// To access x, y
// This is in row-major ordr
*(p + (x * COLUMNS) + y);
I find that, for this kind of code, its better to create helper functions for accessing the elements. Depending on your profiling data, it may make sense to turn these into macros, but be extra careful.
#include <stdio.h> /* For printf */
/* This is the bit that would go in a header, like char2darray.h */
#include <stdlib.h> /* For calloc */
#include <assert.h> /* For assert */
struct Char2DArray
{
int rows;
int columns;
char *values;
};
/* This is the bit that would go in a source file, like char2darray.c */
void C2DA_initialize(struct Char2DArray *array, int rows, int columns)
{
assert(array != 0);
array->values = calloc(rows * columns, sizeof(char));
array->rows = rows;
array->columns = columns;
}
void C2DA_set(struct Char2DArray *array, int row, int column, int value)
{
assert(array != 0);
assert(array->values != 0);
assert(row < array->rows);
assert(row >= 0);
assert(column < array->columns);
assert(column >= 0);
array->values[(row * array->rows) + column] = value;
}
char C2DA_get(struct Char2DArray *array, int row, int column)
{
assert(array != 0);
assert(array->values != 0);
assert(row < array->rows);
assert(row >= 0);
assert(column < array->columns);
assert(column >= 0);
return array->values[(row * array->rows) + column];
}
void C2DA_free(struct Char2DArray *array)
{
free(array->values);
array->values = 0;
}
/* Here's a main.c to use it */
int main()
{
struct Char2DArray a;
C2DA_initialize(&a, 16, 16);
unsigned char c = 0;
int x, y;
for (x=0; x<16; x++) {
for (y=0; y<16; y++) {
C2DA_set(&a, x, y, (char)c);
c++;
}
}
printf("Character with hex value 0x55 is %c\n", C2DA_get(&a, 5, 5));
C2DA_free(&a);
return 0;
}
If the array needs to have a dynamic size, then you either need to make it a pointer or make the array the last member of the struct and play games when allocating the structure size.
Relevant comp.lang.c FAQ entries:
I came across some code that declared a structure like this...
How can I dynamically allocate a multidimensional array?
I found that changing my approach was very useful when faced with a similar problem.
A vector of vectors filled the same task, avoided memory allocation obstacles, and kept the same familiar shorthand. There may be other pitfalls, but I have not encountered them yet.
//Declaration of mValues, undefined size:
std::vector< std::vector<char> > mValues;
//Filling of mValues:
int max_x = 100 ;
int max_y = 100 ;
char char_foo = 'a';
for ( int x = 0; x <= max_x; ++x ) {
vector<char> temp;
for ( int y = 0; y <= max_y; ++y ) {
temp.push_back( char_foo );
}
mValues.push_back( temp );
}
// Referencing with familiar index notation:
mValues[a][b]; //The a-th row's b-th element
If you are struggling with arrays, but strongly desire the familiar indexing language, I have found this to be a good alternative.
Note that indexing order A then B is going to be critical for memory usage when recalling this data. Failure to call the information in an A,B order will be deeply problematic if performance is an issue.

Resources