473,327 Members | 2,065 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,327 software developers and data experts.

Initialising a pointer


I (certainly) hope I know what this function does:

char *fun(void){
char *ptr = "Hello World";

return ptr;
}

It returns a pointer to a string stored somewhere in the memory and is
read-only. Does the following function do the same thing and is the
code legal at all, that is, is the pointer
initialised to point to some string that is read-only?

char *fun(void){
char *ptr;

ptr = "Hello World";

return ptr;
}

I have looked in the FAQ, apologising if it's there somewhere. BTW,
Steve Summit thanks for this very useful resource.

Jesper

Apr 18 '07 #1
19 2433
ma*********@bupkiss.net wrote:
I (certainly) hope I know what this function does:

char *fun(void){
char *ptr = "Hello World";

return ptr;
}
It would be much safer and clearer to make that

const char *fun(void)
It returns a pointer to a string stored somewhere in the memory and is
read-only. Does the following function do the same thing and is the
code legal at all, that is, is the pointer
initialised to point to some string that is read-only?

char *fun(void){
char *ptr;

ptr = "Hello World";

return ptr;
}
Yes, the there isn't any difference.

--
Ian Collins.
Apr 18 '07 #2
ma*********@bupkiss.net said:
>
I (certainly) hope I know what this function does:

char *fun(void){
char *ptr = "Hello World";

return ptr;
}

It returns a pointer to a string stored somewhere in the memory and is
read-only.
Yes. An improvement:

const char *fun(void){
const char *ptr = "Hello World";

return ptr;
}

This will discourage callers from trying to modify the string to which
the function returns a pointer.

Does the following function do the same thing and is the
code legal at all, that is, is the pointer
initialised to point to some string that is read-only?

char *fun(void){
char *ptr;

ptr = "Hello World";

return ptr;
}
Yes, that function does the same thing, yes, the code is legal, (yes, it
is capable of being improved in the same way as the previous one), and
no, the pointer is not initialised. Initialisation is the providing of
a value to an object at the time it is defined. In your example, this
doesn't happen - rather, the object is /assigned/ a value in the
following statement. But yes, it still ends up pointing to a read-only
string.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Apr 18 '07 #3
On Apr 19, 1:24 am, Richard Heathfield <r...@see.sig.invalidwrote:
mail1779...@bupkiss.net said:
I (certainly) hope I know what this function does:
char *fun(void){
char *ptr = "Hello World";
return ptr;
}
It returns a pointer to a string stored somewhere in the memory and is
read-only.
I think this will deliver a pointer to the stack segment as ptr is a
local variable. Pointers to stack segment are not really a good idea
as the content may be overwritten at any time (i.e. with next function
call)
Yes. An improvement:

const char *fun(void){
const char *ptr = "Hello World";

return ptr;

}

This will discourage callers from trying to modify the string to which
the function returns a pointer.
But does not change the fact that the value pointed to may be
overwritten at any moment, as the content lies on the stack.
Did you check the code with gdb (or any debugger?)

Apr 18 '07 #4
go*******@olive-it.ch wrote:
On Apr 19, 1:24 am, Richard Heathfield <r...@see.sig.invalidwrote:
>>mail1779...@bupkiss.net said:

>>>I (certainly) hope I know what this function does:
>>>char *fun(void){
char *ptr = "Hello World";
>> return ptr;
}
>>>It returns a pointer to a string stored somewhere in the memory and is
read-only.
I think this will deliver a pointer to the stack segment as ptr is a
local variable. Pointers to stack segment are not really a good idea
as the content may be overwritten at any time (i.e. with next function
call)
No, it returns a pointer to a string literal, which isn't an automatic
variable. Had it been written as

char *fun(void){
char ptr[] = "Hello World";

return ptr;
}

Your observation would be correct.

--
Ian Collins.
Apr 18 '07 #5
ma*********@bupkiss.net writes:
I (certainly) hope I know what this function does:

char *fun(void){
char *ptr = "Hello World";

return ptr;
}

It returns a pointer to a string stored somewhere in the memory and is
read-only. Does the following function do the same thing and is the
code legal at all, that is, is the pointer
initialised to point to some string that is read-only?

char *fun(void){
char *ptr;

ptr = "Hello World";

return ptr;
}
As others have said, they both do the same thing.

Note that the memory used to store the string may or may not be
"read-only" (depending, in part, on what you mean by that phrase). A
compiler is *allowed* to make string literals writable, and in fact
some compilers do this. On the other hand, a compiler is also allowed
to use OS-level memory protection to make string literals read-only
(or, most likely in an embedded system, even to store them physically
in ROM). Attempting to modify a string literal invokes undefined
behavior.

But thinking of it as "read-only" is a very good habit -- as long as
you don't depend on the compiler to enforce it for you.

Declaring the pointer as "const" is also a good idea. If you do that,
the compiler *will* enforce the "read-only-ness" of the string
literal, at least if you access it via that pointer.
I have looked in the FAQ, apologising if it's there somewhere. BTW,
Steve Summit thanks for this very useful resource.
Thanks for mentioning that; too many posters don't bother.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Apr 19 '07 #6
go*******@olive-it.ch wrote:
On Apr 19, 1:24 am, Richard Heathfield <r...@see.sig.invalidwrote:
mail1779...@bupkiss.net said:
I (certainly) hope I know what this function does:
char *fun(void){
char *ptr = "Hello World";
return ptr;
}
It returns a pointer to a string stored somewhere in the memory and is
read-only.
I think this will deliver a pointer to the stack segment as ptr is a
local variable.
What the hell is a "stack segment"? In C there's no notion of a stack,
which is an implemention detail. But while 'ptr' might be living on the
stack (or as well somewhere else as well) the return value of the func-
tion is the _value_ stored in 'ptr', not 'ptr'. so it doesn't matter a
thing where 'ptr' was living, the caller will receive the address 'ptr'
was pointing to, no matter if 'ptr' still exists after the function re-
turned. And the address that was formerly stored in 'ptr' is the address
of some read-only memory as the OP wrote.
Pointers to stack segment are not really a good idea
as the content may be overwritten at any time (i.e. with next function
call)
Would you care to elaborate what this is supposed to mean?
Yes. An improvement:

const char *fun(void){
const char *ptr = "Hello World";

return ptr;

}

This will discourage callers from trying to modify the string to which
the function returns a pointer.
But does not change the fact that the value pointed to may be
overwritten at any moment, as the content lies on the stack.
Did you check the code with gdb (or any debugger?)
The value pointed to will not be overwritten, just maybe the pointer
that temporarily held the address to the string literal "Hello
world". But 'ptr'doesn't get returned but just what was its value.
Would you be more happy with

const char *fun( void ) {
return "Hello World";
}

which does exactly the same job as the slightly longer version
above?
Regards, Jens
--
\ Jens Thoms Toerring ___ jt@toerring.de
\__________________________ http://toerring.de
Apr 19 '07 #7
On Apr 19, 11:35 am, google...@olive-it.ch wrote:
Richard Heathfield wrote:
const char *fun(void){
const char *ptr = "Hello World";
return ptr;
}


But does not change the fact that the value pointed to may be
overwritten at any moment, as the content lies on the stack.
Did you check the code with gdb (or any debugger?)
Did *you* check it with a debugger?
Perhaps you could paste your debugger output.

Apr 19 '07 #8
On Apr 19, 7:45 am, Ian Collins <ian-n...@hotmail.comwrote:
google...@olive-it.ch wrote:
On Apr 19, 1:24 am, Richard Heathfield <r...@see.sig.invalidwrote:
>mail1779...@bupkiss.net said:
>>I (certainly) hope I know what this function does:
>>char *fun(void){
char *ptr = "Hello World";
> return ptr;
}
>>It returns a pointer to a string stored somewhere in the memory and is
read-only.
I think this will deliver a pointer to the stack segment as ptr is a
local variable. Pointers to stack segment are not really a good idea
as the content may be overwritten at any time (i.e. with next function
call)

No, it returns a pointer to a string literal, which isn't an automatic
variable. Had it been written as

char *fun(void){
char ptr[] = "Hello World";

return ptr;

}
I don't know if a string literal live all the life cycle of the
program? Or does the standard gurantee this. Does static make this
clear?

char *fun(void){
static char *ptr = "Hello World";
/*or even: static char ptr[] = "Hello World";*/
return ptr;
}

Apr 19 '07 #9
lovecreatesbea...@gmail.com wrote:
On Apr 19, 7:45 am, Ian Collins <ian-n...@hotmail.comwrote:
>>
No, it returns a pointer to a string literal, which isn't an automatic
variable. Had it been written as

char *fun(void){
char ptr[] = "Hello World";

return ptr;

}

I don't know if a string literal live all the life cycle of the
program? Or does the standard gurantee this. Does static make this
clear?
They do, although I can't remember off hand where this is explicitly
stated in the standard. The static keyword is unnecessary.

--
Ian Collins.
Apr 19 '07 #10
"lovecreatesbea...@gmail.com" <lo***************@gmail.comwrites:
[...]
I don't know if a string literal live all the life cycle of the
program? Or does the standard gurantee this. Does static make this
clear?
Yes, a the data for a string literal is statically allocated.
C99 6.4.5p5:

In translation phase 7, a byte or code of value zero is appended
to each multibyte character sequence that results from a string
literal or literals.66) The multibyte character sequence is then
used to initialize an array of static storage duration and length
just sufficient to contain the sequence.
char *fun(void){
static char *ptr = "Hello World";
/*or even: static char ptr[] = "Hello World";*/
return ptr;
}
No, declaring "static char *ptr" just causes the pointer object to be
statically allocated; it doesn't affect the string.

Given:

static char ptr[] = "Hello World";

the array ("ptr" is a bad name for an array) is statically allocated,
but here the string literal is used to specify the initialization for
the array. If you omitted the "static" keyword, the array would have
automatic allocation.

String literals are already static. There's no way to specify a
storage class for a string literal, since it's not an object with a
name. You can use the "static" keyword in various places, but it
always applies to something other than the string literal.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Apr 19 '07 #11
ma*********@bupkiss.net wrote:
>
I (certainly) hope I know what this function does:

char *fun(void){
char *ptr = "Hello World";

return ptr;
}

It returns a pointer to a string stored somewhere in the memory and is
read-only. Does the following function do the same thing and is the
code legal at all, that is, is the pointer
initialised to point to some string that is read-only?

char *fun(void){
char *ptr;

ptr = "Hello World";

return ptr;
}
Others have said "yes"; I'd just like to add that

char *fun(void) { return "Hello World"; }

does the same as well.

--
There' no hortage of vowel on Uenet.

Hewlett-Packard Limited registered office: Cain Road, Bracknell,
registered no: 690597 England Berks RG12 1HN

Apr 19 '07 #12
Chris Dollin wrote:
ma*********@bupkiss.net wrote:

>>I (certainly) hope I know what this function does:

char *fun(void){
char *ptr = "Hello World";

return ptr;
}

It returns a pointer to a string stored somewhere in the memory and is
read-only. Does the following function do the same thing and is the
code legal at all, that is, is the pointer
initialised to point to some string that is read-only?

char *fun(void){
char *ptr;

ptr = "Hello World";

return ptr;
}


Others have said "yes"; I'd just like to add that

char *fun(void) { return "Hello World"; }

does the same as well.
But

const char *fun(void) { return "Hello World"; }

would be better.

--
Ian Collins.
Apr 19 '07 #13
Ian Collins wrote:
Chris Dollin wrote:
>Others have said "yes"; I'd just like to add that

char *fun(void) { return "Hello World"; }

does the same as well.
But

const char *fun(void) { return "Hello World"; }

would be better.
I'll not dispute that.

--
"It's just the beginning we've seen" - Colosseum, /Tomorrow's Blues/

Hewlett-Packard Limited registered office: Cain Road, Bracknell,
registered no: 690597 England Berks RG12 1HN

Apr 19 '07 #14

Thanks everyone for all the comments. Naturally, the 'const' qualifier
should be there!

Cheers, Jesper
Apr 19 '07 #15
On Apr 19, 2:00 am, j...@toerring.de (Jens Thoms Toerring) wrote:
google...@olive-it.ch wrote:
On Apr 19, 1:24 am, Richard Heathfield <r...@see.sig.invalidwrote:
mail1779...@bupkiss.net said:
I (certainly) hope I know what this function does:
char *fun(void){
char *ptr = "Hello World";
return ptr;
}
It returns a pointer to a string stored somewhere in the memory and is
read-only.
I think this will deliver a pointer to the stack segment as ptr is a
local variable.

What the hell is a "stack segment"? In C there's no notion of a stack,
which is an implemention detail. But while 'ptr' might be living on the
stack (or as well somewhere else as well) the return value of the func-
tion is the _value_ stored in 'ptr', not 'ptr'. so it doesn't matter a
thing where 'ptr' was living, the caller will receive the address 'ptr'
was pointing to, no matter if 'ptr' still exists after the function re-
turned. And the address that was formerly stored in 'ptr' is the address
of some read-only memory as the OP wrote.
Well let's clarify a bit first:
I was wrong as a parent said: "No, it returns a pointer to a string
literal, which isn't an automatic"
That's not the point however: returning a pointer to a automatic
variable (stored on the stack, generally) is a no-no.
The _value_ stored in a pointer 'ptr' IS 'ptr' and IS a pointer by
nature. Now the value the pointer is referring lies on the stack
and may be overwritten anytime with another value, therefore *ptr may
change its value anytime.
>
Pointers to stack segment are not really a good idea
as the content may be overwritten at any time (i.e. with next function
call)

Would you care to elaborate what this is supposed to mean?
When calling functions two things have to be managed;: the return
address and the parameters. This is generally done with a stack. It's
simple, clean and correct.
Push return address (actual PC) on the stack , push parameters on
stack jump into subroutine. When finished pop parameters and at last
pop return address into PC.
Now: When you use a value or a pointer to a value stored on the stack,
the next fct. call will push its parameter onto the stack and
therefore invalidate the old value.
>
const char *fun(void){
const char *ptr = "Hello World";
return ptr;
}
This will discourage callers from trying to modify the string to which
the function returns a pointer.
But does not change the fact that the value pointed to may be
overwritten at any moment, as the content lies on the stack.
Did you check the code with gdb (or any debugger?)

The value pointed to will not be overwritten, just maybe the pointer
that temporarily held the address to the string literal "Hello
world". But 'ptr'doesn't get returned but just what was its value.
Would you be more happy with

const char *fun( void ) {
return "Hello World";

}

which does exactly the same job as the slightly longer version
above?
Regards, Jens
--
\ Jens Thoms Toerring ___ j...@toerring.de
\__________________________ http://toerring.de

Apr 19 '07 #16
go*******@olive-it.ch said:
On Apr 19, 2:00 am, j...@toerring.de (Jens Thoms Toerring) wrote:
>google...@olive-it.ch wrote:
On Apr 19, 1:24 am, Richard Heathfield <r...@see.sig.invalid>
wrote:
mail1779...@bupkiss.net said:
I (certainly) hope I know what this function does:
char *fun(void){
char *ptr = "Hello World";
return ptr;
}
<snip>
The _value_ stored in a pointer 'ptr' IS 'ptr'
No, it isn't. The value stored in this particular pointer is the address
of that 'H' character at the start of that string literal, which exists
at that same address for the lifetime of the program, guaranteed.
Now the value the pointer is referring lies on the stack
and may be overwritten anytime with another value,
No, you're confused. The value being returned is the address of the
first character of a string literal. This is perfectly okay. It's no
different in principle to a function that allocates memory via malloc,
storing its result in a local pointer, and that then does some initial
tinkering with the memory before returning that value via that local
pointer.
therefore *ptr may
change its value anytime.
The ptr object itself will cease to exist when the function exits, but
its value is still returned to the caller, and that value is the
address of the string literal's first character, which is not about to
change any time soon.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Apr 19 '07 #17
go*******@olive-it.ch wrote:
That's not the point however: returning a pointer to a automatic
variable (stored on the stack, generally) is a no-no.
Returning a pointer to an automatic variable /in that function/ is
a no-no.

Well, strictly, it's perfectly all right: but any /use/ of it gets
you undefined behaviour.

Pointers to automatic variables in function executions that are still
active are fine.
The _value_ stored in a pointer 'ptr' IS 'ptr' and IS a pointer by
nature. Now the value the pointer is referring lies on the stack
and may be overwritten anytime with another value, therefore *ptr may
change its value anytime.
Yes. Any use of such a pointer provokes undefined behaviour.
When calling functions two things have to be managed;: the return
address and the parameters. This is generally done with a stack. It's
simple, clean and correct.
Push return address (actual PC) on the stack , push parameters on
stack jump into subroutine. When finished pop parameters and at last
pop return address into PC.
That's one way of doing it, yes. Quite often parameters are /not/
passed on the stack, but in registers. (Those registers may need
to be stored on the stack later, but then again, they may not.)
Now: When you use a value or a pointer to a value stored on the stack,
the next fct. call will push its parameter onto the stack and
therefore invalidate the old value.
I know what you mean (I think), but you've said it badly. When you
use a pointer to an automatic which was allocated in a call /that
has terminated/, these bad things may happen. (Or not. Depending.)

--
"We are on the brink of a new era, if only --" /The Beiderbeck Affair/

Hewlett-Packard Limited registered office: Cain Road, Bracknell,
registered no: 690597 England Berks RG12 1HN

Apr 19 '07 #18
On Apr 18, 9:41 pm, Keith Thompson <k...@mib.orgwrote:
"lovecreatesbea...@gmail.com" <lovecreatesbea...@gmail.comwrites:

[...]
I don't know if a string literal live all the life cycle of the
program? Or does the standard gurantee this. Does static make this
clear?

Yes, a the data for a string literal is statically allocated.
C99 6.4.5p5:

In translation phase 7, a byte or code of value zero is appended
to each multibyte character sequence that results from a string
literal or literals.66) The multibyte character sequence is then
used to initialize an array of static storage duration and length
just sufficient to contain the sequence.
char *fun(void){
static char *ptr = "Hello World";
/*or even: static char ptr[] = "Hello World";*/
return ptr;
}

No, declaring "static char *ptr" just causes the pointer object to be
statically allocated; it doesn't affect the string.

Given:

static char ptr[] = "Hello World";

the array ("ptr" is a bad name for an array) is statically allocated,
but here the string literal is used to specify the initialization for
the array. If you omitted the "static" keyword, the array would have
automatic allocation.
Thank you, it's more clear to me now.
String literals are already static. There's no way to specify a
storage class for a string literal,
If there is a local `char *' pointer refers to a very long string,
then the storage for that string won't be released until the program
ends, right?

{
char *str_with_max_len = "themostlongstring... ...inclanguage";
}
since it's not an object with a name.
The strings are array of chars, and they have no name, only can be
refered to by pointers. Do I understand this right?

Apr 19 '07 #19
Richard Heathfield <rj*@see.sig.invalidwrites:
go*******@olive-it.ch said:
>On Apr 19, 2:00 am, j...@toerring.de (Jens Thoms Toerring) wrote:
>>google...@olive-it.ch wrote:
On Apr 19, 1:24 am, Richard Heathfield <r...@see.sig.invalid>
wrote:
mail1779...@bupkiss.net said:

I (certainly) hope I know what this function does:

char *fun(void){
char *ptr = "Hello World";

return ptr;
}
<snip>
>The _value_ stored in a pointer 'ptr' IS 'ptr'

No, it isn't. The value stored in this particular pointer is the address
of that 'H' character at the start of that string literal, which exists
at that same address for the lifetime of the program, guaranteed.
[...]

Exactly.

To expand on the point, returning the *value* of a local variable is
perfectly fine. There are cases where *using* that returned value can
cause problems.

For example:

int func1(void)
{
int n = 2 + 2;
return n;
}

This returns the value of n, which happens to be 4. The variable
itself ceases to exist when we return from the function, but that's
ok; we copied its value before it ceased to exist.

char *func2(void)
{
char *ptr = "Hello, World";
return ptr;
}

Again, there's no problem. We're just returning the value of a local
variable. The value of that variable happens to be a pointer to a
string, but that string, since it's the result of a string literal,
exists for the lifetime of the program, so there's also no problem
using that value; it will continue to point to "Hello, World" even
after the pointer object "ptr" has ceased to exist.

int *func3(void)
{
int n = 42;
int *ptr = &n;
return ptr;
}

Now we have a potential problem. Again, we're just returning the
value of a local variable; as in the other two examples, this doesn't
directly cause any problems. But the *value* of that local variable,
and therefore the value returned from the function, happens to be a
pointer to the local variable n. After we've returned from the
function, both ptr and n have ceased to exist. The fact that ptr no
longer exists isn't a problem, since we copied its value while it
still existed. The fact that n no longer exists *is* a problem, since
we're still holding a pointer to it. Returning the value doesn't
cause the problem; attempting to use the value will cause a problem.
(A subtle point: even looking at the pointer value without
dereferencing it invokes undefined behavior.)

So don't do that.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Apr 19 '07 #20

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

Similar topics

6
by: Mattias Brändström | last post by:
Hello all! I am trying to write code that allows me to initialise one of my classes inline (with a vector like structure). Inline might not be the best term to use here but I can't think of any...
8
by: nrhayyal | last post by:
hi all, is it a good idea to assign object to pointers without initialising it to NULL? suppose if i have a class TEST class ELEMENT { private: int a; string s1;
2
by: shan_rish | last post by:
Hi CLCers, In the below program the error message while compiling is /home1/murugan/prog/cprog >cc -o struct_eval struct_eval.c cc: "struct_eval.c", line 14: error 1549: Modifiable lvalue...
107
by: DaveC | last post by:
I always used to initialise variables at declaration, then a couple of colleagues started telling me it was bad practice and that the compiler should be left to spot the use of uninitilised...
0
by: jl_post | last post by:
On Jun 27, 7:06 am, Angus <anguscom...@gmail.comwrote: To be honest, I don't know of a simple way to do what you want using both "const" and a non-pointer. But if you don't mind using a const...
33
by: Adam Chapman | last post by:
Hi, Im trying to migrate from programming in Matlab over to C. Im trying to make a simple function to multiply one matrix by the other. I've realised that C can't determine the size of a 2d...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
1
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
1
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...

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.