LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 03-24-2007, 07:30 PM   #1
kourama
LQ Newbie
 
Registered: Sep 2006
Distribution: Mint64 w/KDE
Posts: 17

Rep: Reputation: 0
SOLVED: c gurus: whats the diff? "var[]" and "*var"?


I have used "char *var" and "char var[]" more or less interchangeably until it stopped working recently. I have seen the following problem on two occasions. The first time I thought it was a buggy compiler, now I think I might be missing a crucial piece of knowledge.

I have a function which refers to an external array of chars, very plan and boring. The following works:

extern volatile char myvar[];
.
.
char myothervar=myvar[0];

...and the following does not work:

extern volatile char *myvar;
.
.
char myothervar=myvar[0];

...Why aren't they equivalent? For example, why doesn't this fail:

char myvar[]="something";

char myfunc( char *ptr) { return ptr[0]; }
.
.
char myothervar=myfunc(myvar);

. Not a life-or-death problem, but it's something I'd like to understand.

thanks.

Last edited by kourama; 03-26-2007 at 03:28 PM. Reason: let everyone know it's solved
 
Old 03-24-2007, 10:35 PM   #2
cjcox
Member
 
Registered: Jun 2004
Posts: 307

Rep: Reputation: 42
Quote:
Originally Posted by kourama
I have used "char *var" and "char var[]" more or less interchangeably until it stopped working recently. I have seen the following problem on two occasions. The first time I thought it was a buggy compiler, now I think I might be missing a crucial piece of knowledge.

I have a function which refers to an external array of chars, very plan and boring. The following works:

extern volatile char myvar[];
.
.
char myothervar=myvar[0];

...and the following does not work:

extern volatile char *myvar;
.
.
char myothervar=myvar[0];
It's a subtle difference, but the first one says myvar is
a char array. The second says that myvar is a pointer
to character array.

Without the full context, it's hard to know what exactly
is failing. Both examples compile just fine for me.

Can you provide a bit more detail?

Quote:

...Why aren't they equivalent? For example, why doesn't this fail:

char myvar[]="something";

char myfunc( char *ptr) { return ptr[0]; }
.
.
char myothervar=myfunc(myvar);

. Not a life-or-death problem, but it's something I'd like to understand.

thanks.
How is it failing? More detail please.
 
Old 03-25-2007, 04:21 AM   #3
slzckboy
Member
 
Registered: May 2005
Location: uk - Reading
Distribution: slackware 14.2 kernel 4.19.43
Posts: 462

Rep: Reputation: 30
Code bugs are nearly always down to the programmer.

You should always assume that the fault is with your code until you have exhausted every possibility.

char buffer[]="hello mum" allocates enough memory to store the string plus its null terminator.
thus you can reference buffer[0] or buffer[1] or buffer[4]

up until buffer[strlen(buffer)] where buffer[(strlen(buffer)]

will = '\0'

however...
Code:
extern volatile char *myvar;
you havn't inititialised *myvar to point to any memory within the memory space of your program.

Unless you have done so somewhere else in your code???

Thus it is a wild pointer pointing to some random location in memory,most probably a locaton in memory that your pogram dosn't have access to.

If you declare a pointer to char you have to make sure that it then points to something meaningful,i.e legal memory.
 
Old 03-25-2007, 10:01 AM   #4
kourama
LQ Newbie
 
Registered: Sep 2006
Distribution: Mint64 w/KDE
Posts: 17

Original Poster
Rep: Reputation: 0
Here is an example with details (Sorry, the editor gobbled up my tabs, so the formatting is not pretty):

system details:
$ uname -a
Linux fnort 2.4.33.3 #1 Fri Sep 1 01:48:52 CDT 2006 i686 pentium4 i386 GNU/Linux


compiler:
$ gcc -v
Reading specs from /usr/lib/gcc/i486-slackware-linux/3.4.6/specs
Configured with: ../gcc-3.4.6/configure --prefix=/usr --enable-shared --enable-threads=posix --enable-__cxa_atexit --disable-checking --with-gnu-ld --verbose --target=i486-slackware-linux --host=i486-slackware-linux
Thread model: posix
gcc version 3.4.6


makefile:
Code:
$ cat Makefile
CC=gcc
COPTS=-Wall -g
SRCLIST=a.c b.c
OBJLIST= $(SRCLIST:.c=.o)
TARGET=a

$(TARGET) : $(OBJLIST)
        $(CC) $(COPTS) $(OBJLIST) -o $(TARGET)

$(OBJLIST) : %.o : %.c
        $(CC) $(COPTS) -c $<

clean :
        rm -f *.o
source1:
Code:
$ cat a.c
#include <stdio.h>
#include <stdlib.h>

char myarray0[]="foo";
char myarray1[]="bar";

extern void b( void );

void aa( char *arg0, char *arg1) {
  printf("aa says:\n");
  printf("&arg0=0x%08x\n",(int) arg0);
  printf("&arg1=0x%08x\n",(int) arg1);
  printf("\n");
}

int main(int argc, char **argv) {

  printf("a says:\n");
  printf("&myarray0=0x%08x\n",(int) myarray0);
  printf("&myarray1=0x%08x\n",(int) myarray1);
  printf("\n");
  aa(myarray0,myarray1);
  b();

  return 0;
}
source2:
Code:
$ cat b.c
#include <stdio.h>

extern char *myarray0;
extern char myarray1[];

void b( void ) {
  printf("b says:\n");
  printf("&myarray0=0x%08x\n",(int) myarray0);
  printf("&myarray1=0x%08x\n",(int) myarray1);
}
execution log:
$ a
a says:
&myarray0=0x0804974c
&myarray1=0x08049750

aa says:
&arg0=0x0804974c
&arg1=0x08049750

b says:
&myarray0=0x006f6f66
&myarray1=0x08049750


I've written functions like aa many times, but somehow, in 20+ years of C programming, I've never had occasion to use the "extern char *" line before. Actually I know why I've never used it before, I purposely avoided allowing one module to meddle with another's variables, but in the situation I'm in now, I can't avoid it.

So, the question is, why is there a semantic difference between the "char *" reference in the aa function's arglist and the "char *" reference in b's extern var list?

Last edited by kourama; 03-25-2007 at 04:59 PM. Reason: formatted code
 
Old 03-25-2007, 12:37 PM   #5
slzckboy
Member
 
Registered: May 2005
Location: uk - Reading
Distribution: slackware 14.2 kernel 4.19.43
Posts: 462

Rep: Reputation: 30
I would just do it like this,although I guess its not going to answer your question to your satisfaction?!!

a.c
Code:
#include <stdio.h>
#include <stdlib.h>

char myarray0[]="foo";
char myarray1[]="bar";

void b( void );

void aa( char *arg0, char *arg1) {
        printf("aa says:\n");
        printf("&arg0=0x%08x\n",(int) arg0);
        printf("&arg1=0x%08x\n",(int) arg1);
        printf("\n");
}

int main(int argc, char **argv) {

        printf("a says:\n");
        printf("&myarray0=0x%08x\n",(int) myarray0);
        printf("&myarray1=0x%08x\n",(int) myarray1);
        printf("\n");

        aa(myarray0,myarray1);
        b();

        return 0;
 }
b.c

Code:
#include <stdio.h>


 void b( void ) {

 extern char myarray0[];
 extern char myarray1[];

 printf("b says:\n");
 printf("&myarray0=0x%08x\n",(int) myarray0);
 printf("&myarray1=0x%08x\n",(int) myarray1);
 }
output log

Code:
a says:
&myarray0=0x080495f4
&myarray1=0x080495f8

aa says:
&arg0=0x080495f4
&arg1=0x080495f8

b says:
&myarray0=0x080495f4
&myarray1=0x080495f8
p.s

pls try and use format tags wen posting your code.Thnks
 
Old 03-25-2007, 12:39 PM   #6
slzckboy
Member
 
Registered: May 2005
Location: uk - Reading
Distribution: slackware 14.2 kernel 4.19.43
Posts: 462

Rep: Reputation: 30
I guess the way you were doing it the compiler was interpreting it as your declaring another external variable instead of referencing it against the previously declared one?!!
 
Old 03-25-2007, 04:57 PM   #7
kourama
LQ Newbie
 
Registered: Sep 2006
Distribution: Mint64 w/KDE
Posts: 17

Original Poster
Rep: Reputation: 0
Quote:
Originally Posted by slzckboy
I guess the way you were doing it the compiler was interpreting it as your declaring another external variable instead of referencing it against the previously declared one?!!
If you look at the value that b gives for the address of myarray0, it is in fact the contents of the array (0x006f6f66 is "foo\0" in little-endian format). For some reason it dereferences the variable and returns value instead of address. If I refer to "&myarray0" instead of just "myarray0" I'll get the correct address of myarray0; this seems wrong to me.

Quote:
Originally Posted by slzckboy
p.s

pls try and use format tags wen posting your code.Thnks
Sorry for the ugliness, will fix.
 
Old 03-26-2007, 03:02 AM   #8
bigearsbilly
Senior Member
 
Registered: Mar 2004
Location: england
Distribution: Mint, Armbian, NetBSD, Puppy, Raspbian
Posts: 3,515

Rep: Reputation: 239Reputation: 239Reputation: 239
Quote:
20+ years of C programming,
and you don't know the difference?
are you sure?

it's quite simple,

char buffer[100] is a buffer of memory that can store 100 bytes.
char *p is a pointer that typically points at a char buffer or array.

you must make sure that what *p points at is a valid buffer.
 
Old 03-26-2007, 06:52 AM   #9
IBall
Senior Member
 
Registered: Nov 2003
Location: Perth, Western Australia
Distribution: Ubuntu, Debian, Various using VMWare
Posts: 2,088

Rep: Reputation: 62
Don't you have to use malloc() if you want to create an array using *ptr?

I think this is equivalent:
Code:
char *string1 = "Hello World";
char string2[] = "Hello World";
But this is not allowed, as you have not assigned memory to the pointer:
Code:
char *string3;
*string3 = "Hello World";
--Ian
 
Old 03-26-2007, 09:24 AM   #10
kourama
LQ Newbie
 
Registered: Sep 2006
Distribution: Mint64 w/KDE
Posts: 17

Original Poster
Rep: Reputation: 0
Quote:
Originally Posted by IBall
Don't you have to use malloc() if you want to create an array using *ptr?

I think this is equivalent:
Code:
char *string1 = "Hello World";
char string2[] = "Hello World";
But this is not allowed, as you have not assigned memory to the pointer:
Code:
char *string3;
*string3 = "Hello World";
--Ian
actually, what you're doing is valid, you just have a syntax error, what you want is:

char *string3;
string3="Hello World";


when you link, the "Hello World" string is stored in the .rodata section, and the variable string3 points to it. no problemo. Remeber that "Hello World" returns a pointer to that string, which is why your example above with string1 and string2 work. When you are declaring the variable, the '*' indicates that you mean a pointer. In the body of the code '*' means that your are derefrencing that pointer.

Quote:
Originally Posted by bigearsbilly
and you don't know the difference?
are you sure?

it's quite simple,

char buffer[100] is a buffer of memory that can store 100 bytes.
char *p is a pointer that typically points at a char buffer or array.

you must make sure that what *p points at is a valid buffer.
Yes, there's a conceptual difference in your example, but in the compiled code both are simply pointers to locations in memory. The "[100]" tells the linker to allocated enough space in the .bss or .data sections of your program (depending on whether or not it's initialized) and tells the compiler how many elements exist so that it can check to see if you do something bad like make a reference to buffer[125].

I appreciate the responses guys, but please pay attention to the example. There is no issue with initialization, the issue is that "char *" means something different when used to declare a reference to an external variable in b.c and when used to declare a reference to an argument in the aa function in a.c. Why is there a different meaning assigned when the context strongly suggests (IMHO) that they should be identical?

Maybe I should contact the GCC developers group on this one.
 
Old 03-26-2007, 03:26 PM   #11
kourama
LQ Newbie
 
Registered: Sep 2006
Distribution: Mint64 w/KDE
Posts: 17

Original Poster
Rep: Reputation: 0
OK, a wiser sould than I pointed out the flaw in my thinking.

Here's what's going on:

In the declaration:
Code:
extern char *myarray0;
I am effectively casting the first 4 bytes of the array myarray0 from a.c to a pointer to an array, which is equivalent to

Code:
char *myarray0_in_b= (char *) (* (int *) myarray_in_a);
which is, of course, very wrong.
 
Old 03-26-2007, 05:11 PM   #12
slzckboy
Member
 
Registered: May 2005
Location: uk - Reading
Distribution: slackware 14.2 kernel 4.19.43
Posts: 462

Rep: Reputation: 30
ouch...messy
well I'm glad you have satisfied your curiosity and got it clear in your head.

you can sleep easy now :0)

cheers
 
Old 03-27-2007, 04:55 AM   #13
nmh+linuxquestions.o
Member
 
Registered: Feb 2007
Posts: 135

Rep: Reputation: 15
Quote:
Originally Posted by slzckboy
ouch...messy
well I'm glad you have satisfied your curiosity and got it clear in your head.

you can sleep easy now :0)

cheers
I found the q&a enlightening (as one who does not usually work with c). Thanks for the question, answers and summary.
 
Old 03-27-2007, 08:46 AM   #14
jim mcnamara
Member
 
Registered: May 2002
Posts: 964

Rep: Reputation: 36
This is not good. Nobody mentioned the C99 standard and what it says:

1. char var[]="abc";
This creates an array of char which is modifable
2. char *var="abc";
This creates an array of char, the results of modifying it are unspecified.

FYI "unspecified" is a code word for "It may or may not work. But don't expect to be able to port the code just because some compiler writer was nice enough to make it work for your platform."
In short "don't modify it"

3. char *var=NULL; [ or char *var; ] is a pointer to char and is modifable.
 
Old 03-27-2007, 08:54 AM   #15
bigearsbilly
Senior Member
 
Registered: Mar 2004
Location: england
Distribution: Mint, Armbian, NetBSD, Puppy, Raspbian
Posts: 3,515

Rep: Reputation: 239Reputation: 239Reputation: 239
of course,
"abc" is a constant string compiled in. which the compliler can put where it likes.
char *var is pointing to it.

some platforms may have read only data sections, which makes perfect sense, hence
it will spit it's dummy out if you write to it.

It's easy
char * should point at some previously allocated data.
char [] will have space allocated in your heap or stack space.

char [] is a buffer
char * is a pointer


you are responsible for not blowing holes in memory.

Last edited by bigearsbilly; 03-27-2007 at 08:57 AM.
 
  


Reply

Tags
array, pointers, reference



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
newbie question: whats the difference between "su root", "su" and "su -&quo mojarron Slackware 9 12-07-2009 04:08 PM
Renamed bogus "/var/mail/macleanl" into "/var/mail/BOGUS.macleanl.xPVB" paul_mat Linux - Networking 1 07-04-2006 12:50 PM
using symlinks for /home/"username" and /var/www/html hamza11050 Linux - Networking 10 08-05-2005 10:36 PM
Boot messages not the same as "dmesg" or "/var/log/messages"? massai Linux - General 5 03-10-2004 12:18 AM
sshd error " bad owner or mode for /var/empty" piraxter Slackware 1 09-09-2003 11:57 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 02:33 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration