473,386 Members | 1,908 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,386 software developers and data experts.

Problem with va_ macros and arrays of arrays

Since a few days ago I have been working with the program I post
below (a school assignment). The purpose of the program is to work
with the va_ macros (stdarg.h) and arrays of arrays, hopefully
learning a little bit in the process.

The objective of the fn_memset function is to set all the chars in
the arrays passed (of type array N of array M of char) to a
specific char, somewhat similar to what the standard function
memset does:

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>

#define N_MAT 10
#define T_NOM 40
#define T_NIF 10
#define T_POB 15

char alu_nom[N_MAT][T_NOM];
char alu_nif[N_MAT][T_NIF];
char alu_pob[N_MAT][T_POB];

void fn_memset(char car, int n_args, ...);

int main(void)
{
int i;

fn_memset('A', 6, T_NOM, alu_nom, T_NIF, alu_nif,
T_POB, alu_pob);

for (i = 0; i < N_MAT; i++){
alu_nom[i][T_NOM - 1] = '\0';
alu_nif[i][T_NIF - 1] = '\0';
alu_pob[i][T_POB - 1] = '\0';
}

puts("Array alu_nom[][]:");
for (i = 0; i < N_MAT; i++)
printf("%s\n", alu_nom[i]);
printf("\n");

puts("Array alu_nif[][]:");
for (i = 0; i < N_MAT; i++)
printf("%s\n", alu_nif[i]);
printf("\n");

puts("Array alu_pob[][]:");
for (i = 0; i < N_MAT; i++)
printf("%s\n", alu_pob[i]);
printf("\n");

return EXIT_SUCCESS;
}

void fn_memset(char car, int n_args, ...)
{
int i, j, tam;
char *aux;
va_list pa;

va_start(pa, n_args);
while(n_args > 0){

tam = va_arg(pa, int);
aux = va_arg(pa, char *);

for (i = 0; i < N_MAT; i++)
for (j = 0; j < tam; j++)
*(aux + i * tam + j) = car;

n_args -= 2;
}
va_end(pa);
}

The compiler (and splint) didn't emit any errors, and the program
produced the expected output with no run-time errors but I think I
just got 'lucky behaviour'.

This because I discovered (with horror ;-) that the operation of
'flattening an array' is illegal as the pointer to char moves from
one array M of char to another one, or at least that's what I
found in the book 'Pointers on C' by Kenneth A. Reek.

As I'm still a beginner in C without a copy of the standard I
don't want to fall into the scenario "OK let's try such and such
and if it works in my system then ...". Instead what better than
asking the pros of comp.lang.c a few questions? ;-)

First, can the function fn_memset be implemented with standard C?

Second, can a cast consist of values that are calculated at run-
time? For example:

void fn_memset(void *a, size_t n, size_t m)
{
size_t i, j;

for (i = 0; i < n; i++)
for (j = 0; j < m; j++)
((char (*)[m]) a)[i][j] = 'x';
}

Third (and related), can a pointer declaration consist of values
that are calculated at run-time? In a similar vein:

void fn_memset(void *a, size_t n, size_t m)
{
size_t i, j;
char (*foo)[m] = a;

for (i = 0; i < n; i++)
for (j = 0; j < m; j++)
foo[i][j] = 'x';
}

Last question, as you can see I have many holes in my knowledge of
C so please can someone point me to didactic material (preferably
online) about the correct use of declarations, casting and
typedef's?

Thanks for your time.
Nov 14 '05 #1
1 2179
On 22 Mar 2005 14:01:15 GMT, rir3760 <in*********@myrealbox.com>
wrote: (and no one else seems to have replied?)
Since a few days ago I have been working with the program I post
below (a school assignment). The purpose of the program is to work
with the va_ macros (stdarg.h) and arrays of arrays, hopefully
learning a little bit in the process.

The objective of the fn_memset function is to set all the chars in
the arrays passed (of type array N of array M of char) to a
specific char, somewhat similar to what the standard function
memset does:
<snip> char alu_nom[N_MAT][T_NOM];
char alu_nif[N_MAT][T_NIF];
char alu_pob[N_MAT][T_POB];
Aside: it appears here you want to have several (parallel) pieces of
data or attributes about a series of entities. You can also achieve
that with an array of struct, or possibly a pointer to a dynamic array
of struct, and usually that's easier to code and maintain. For
learning of course you should learn both (and in general all options),
and if your teacher has decided to go this way first, or at this time,
I realize that's not your responsibility.

<snip> fn_memset('A', 6, T_NOM, alu_nom, T_NIF, alu_nif,
T_POB, alu_pob); <snip> void fn_memset(char car, int n_args, ...)
{
int i, j, tam;
char *aux;
va_list pa;

va_start(pa, n_args);
while(n_args > 0){

tam = va_arg(pa, int);
aux = va_arg(pa, char *);

for (i = 0; i < N_MAT; i++)
for (j = 0; j < tam; j++)
*(aux + i * tam + j) = car;
I hope you know that's equivalent to aux[i*tam+j] = car;
which is more usual and thus easier to read.
n_args -= 2;
}
va_end(pa);
}

The compiler (and splint) didn't emit any errors, and the program
produced the expected output with no run-time errors but I think I
just got 'lucky behaviour'.

This because I discovered (with horror ;-) that the operation of
'flattening an array' is illegal as the pointer to char moves from
one array M of char to another one, or at least that's what I
found in the book 'Pointers on C' by Kenneth A. Reek.
For a non-char array say int x[3][6] using x[0][12] to access x[2][0]
is technically illegal, but in practice it always works. Moreover,
when accessing any object (area of memory) using a pointer to
specifically character type (plain char, signed char, or unsigned
char), you are guaranteed to be able to address all the bytes, and
store to them (as you do); in C99 you are guaranteed to fetch them
using pointer to unsigned char, which cannot have padding bits or trap
representations, but maybe not signed char, and thus not plain char if
it is signed, although in practice those work too. In C89 this was
worded more loosely and it may be guaranteed that pointer to signed
char also works; it certainly does in practice.

You are actually doing something different: you are passing a
char(*)[N] as a vararg thus without any conversion and picking it up
as char*. This is not guaranteed to work; different kinds of pointers,
that is to different types, can have different representations (and
even sizes). In practice I don't know of and can't imagine an
implementation where a pointer to char array would have any reason to
be different from a pointer to char, but in theory it could happen. (I
_do_ know rare cases where int *, or int(*)[N], or struct foo * or
struct foo (*)[N], differs from char * and char (*)[N] and void *.)

If you cast the pointer _in the call_ it would thus be totally safe:
fn_memset ('A', 2, T_NOM, (char*)alu_nom);

Alternatively, pointer to array-unbounded is required to be compatible
with pointer to array of any fixed size, so you could pick them up as:
typedef chararyptr char (*)[];
chararyptr auxa = va_arg (pa, chararyptr);
char * aux = *auxa /* or & * (*aux) to be explicit */
/* or just use (*auxa)[i*m+j] or similar */
(The typedef is needed because the typename in va_arg must be validly
'pointerized' by just appending an asterisk.)

That said, for real code you should just use memset(); that's what
it's there for, it's (more) easily understood by anyone reading your
code, it's one less thing to write and maintain and manage, and it's
probably better optimized especially across platforms.
As I'm still a beginner in C without a copy of the standard I
don't want to fall into the scenario "OK let's try such and such
and if it works in my system then ...". Instead what better than
asking the pros of comp.lang.c a few questions? ;-)
Very good thinking. "What my implementation does" is not the right
criteria _especially_ for C which deliberately leaves quite a bit of
leeway -- some people feel too much -- for implementation variations.
The standard isn't written as a tutorial and is difficult to read
unless you already understand the concepts pretty well -- which it
appears to me you do -- but if you want it you can purchase it in PDF
form for individual use for USD 18 from ANSI, the US national body, at
webstore.ansi.org, or as a deadtree book from Wiley with BSI the UK
national body ISBN 0470845732 I believe about USD 40; or you can get
the last publicly circulated draft in PDF, txt, and IIRC ps from the
committee website std.dkuug.dk/JTC1/SC22/WG14/documents/n869/ .
The draft is not exactly the standard, there were some small changes,
but it is close enough to do a good deal of learning from. But, if you
use it and need to post a citation here regarding some question, say
it's from n869, so if you happen upon one of the few points that is
different we will understand and not think you incompetent.

There have actually been two "TCs" (Technical Corrigenda) to C99,
which are both available free (last I looked) from ANSI, and I've been
told the Wiley book incorporates TC1. Again these changes are minor.
First, can the function fn_memset be implemented with standard C?
See above.
Second, can a cast consist of values that are calculated at run-
time? For example: <snip> ((char (*)[m]) a)[i][j] = 'x';
}

Third (and related), can a pointer declaration consist of values
that are calculated at run-time? In a similar vein: <snip> char (*foo)[m] = a;
The bound(s) of a nonstatic nonmember array type (only) can be runtime
values, including those two examples, in standard C99 (not yet widely
implemented) or in GNU-C89 aka GCC as an extension (very widely
available). Some other cases that would match your question as worded,
like an array bound in a struct, a bitfield in a struct, or even a
(stupidly placed) enum, cannot.
Last question, as you can see I have many holes in my knowledge of
C so please can someone point me to didactic material (preferably
online) about the correct use of declarations, casting and
typedef's?

I'd say you're doing pretty well to be asking questions at this level,
and as far as my opinion matters (which isn't very far) you're welcome
to continue. There's always the FAQ, at the usual places and a
slightly old version at http://www.eskimo.com/~scs/C-faq/top.html .
Beyond that I don't have any good, er, pointers.

- David.Thompson1 at worldnet.att.net
Nov 14 '05 #2

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

699
by: mike420 | last post by:
I think everyone who used Python will agree that its syntax is the best thing going for it. It is very readable and easy for everyone to learn. But, Python does not a have very good macro...
24
by: Bangalore | last post by:
Hi all, I have a problem in accessing elements using overloaded operator . Consider, const int SIZE=10; int FALSE=0; class Array { private: int x; public:
7
by: hierro | last post by:
I have a list of functions (all with suffix T). For each one, I need to implement the following: FunctionT() { if (some_condition) { // do some conversion first FunctionW(); // then do some...
6
by: Roman Mashak | last post by:
Hello, All! I would like to use this macro to substitute type of variable, but it doesn't work by now: typedef enum table_type_e { INT, FLOAT, DOUBLE } table_type_t;
16
by: Shwetabh | last post by:
Hi, This is a question asked to me in an interview. I haven't been able to figure out an answer for it. Please try to see what can be done about the following problem. /* I have been given two...
2
by: ajikoe | last post by:
Hi, I tried to follow the example in swig homepage. I found error which I don't understand. I use bcc32, I already include directory where my python.h exist in bcc32.cfg. /* File : example.c...
4
by: NT | last post by:
Hi there! I am puzzled by what I think must be a subtlety of C++ when list-initializing member variables in derived classes... Here's what I mean... class A { // warning l337proggy alert!...
33
by: Robert Seacord | last post by:
When writing C99 code is a reasonable recommendation to use inline functions instead of macros? What sort of things is it still reasonable to do using macros? For example, is it reasonable to...
9
by: weidongtom | last post by:
Hi, I've written the code that follows, and I use the function add_word(), it seems to work fine *before* increase_arrays() is called that uses realloc() to allocate more memory to words. But...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.