LinuxQuestions.org
Visit Jeremy's Blog.
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 11-13-2012, 05:25 AM   #1
rm_-rf_windows
Member
 
Registered: Jun 2007
Location: Europe
Distribution: Ubuntu
Posts: 292

Rep: Reputation: 27
C pointers and strings


Hello,

I am creating my own little C pointer reference because I've never been able to completely figure out why I've had so many problems with them in the past. In university, we had never had a course in C and suddenly had a systems course which necessitated programming in C. I had to juggle learning C and a very difficult systems course and had a very hard time, notably with pointers (Segmentation faults, etc.).

This time round, I'm just learning good old plain C, the latin of programming, and I'm enjoying it. I now realize that those who know how to program in C probably don't realize how complex pointers are in C, some things work with certain values (numbers) but suddenly are different with other values or in other contexts (arrays, strings)...

Now with my question...

This works. No problem:
Code:
    double *dPtr;
    dPtr = (double *)malloc(sizeof(double));
    *dPtr = 3.14159;
    printf("dPtr points to the heap at value %f.\n", *dPtr);
    free(dPtr);
This works:
Code:
    char *string;
    char *string;
    string = (char *)malloc(30 * sizeof(char));
    scanf(" %s", string);
    //string = "Hello, my name is Johnny";    
    //strcpy(string, "Helly, my name is Johnny");
    printf("'string' points to the heap at value %s.\n", string);
    free(string);
This does not work (Why? How can I make it work?). It is the free(string) that causes the problem:
Code:
    char *string;
    string = (char *)malloc(30 * sizeof(char));
    //scanf(" %s", string);
    string = "Hello, my name is Johnny";    
    //strcpy(string, "Helly, my name is Johnny");
    printf("'string' points to the heap at value %s.\n", string);
    free(string);
This doesn not work either (same problem):
Code:
    char *string;
    string = (char *)malloc(30 * sizeof(char));
    //scanf(" %s", string);
    //string = "Hello, my name is Johnny";    
    strcpy(string, "Helly, my name is Johnny");
    printf("'string' points to the heap at value %s.\n", string);
    free(string);
Why? How can I make it all work?

Thx!

rm

Last edited by rm_-rf_windows; 11-13-2012 at 05:26 AM.
 
Old 11-13-2012, 05:35 AM   #2
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
The third example that you indicated doesn't work is because you are attempting to free a pointer ('string') that is referencing an immutable string on the heap. Try to comprehend this sequence of events:

1. You declare 'string', but it is pointing to nothing (ie a dangling pointer)

2. You allocate space for 'string', such that now, if memory is available, 'string' is pointing to a valid region on the heap.

3. You relocate where 'string' is pointing by setting it to reference (point) to a hard-coded string sitting somewhere in memory. This effectively created a memory leak.


The fourth example should work just fine; I'm not sure why you indicated otherwise.
 
Old 11-13-2012, 05:38 AM   #3
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 21,838

Rep: Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308
in the third case:
Code:
char *string;
# here you allocate memory (of 30 chars) and store the pointer in the variable string
string = (char *)malloc(30 * sizeof(char));
//scanf(" %s", string);
# here you have another text which is stored in another part of the memory, you have not allocated any space for it
# (this is a constant and stored together with the compiled code in the executable or library)
# and also you store this pointer in the variable string again, the previous value therefore lost
string = "Hello, my name is Johnny";    
//strcpy(string, "Helly, my name is Johnny");
printf("'string' points to the heap at value %s.\n", string);
# here you want to free up the memory pointed by string, which was never malloced.
free(string);
I think you have another kind of problem with your last example, please check it again...
 
Old 11-13-2012, 12:21 PM   #4
Peverel
Member
 
Registered: May 2009
Location: Chelmsford, England
Distribution: OpenSuse 12.2 and 13.2, Leap 4.2
Posts: 128

Rep: Reputation: 24
I do not know what you mean by "work". I copied the last example, it compiled and ran. You do not test after the call of free, so I don't know if that behaved itself.
 
Old 11-13-2012, 12:55 PM   #5
johnsfine
LQ Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,286

Rep: Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197
I don't see any reason why your fourth example acted like your third. Others seem to have looked at that detail more carefully and also see no reason. So I expect that was operator error, such as you forgot to recompile after editing to create the fourth example and before running to test what you thought was the fourth example.

Quote:
Originally Posted by rm_-rf_windows View Post
I now realize that those who know how to program in C probably don't realize how complex pointers are in C
I always found pointers in C quite simple. But I do understand one of the sources of your confusion:

When T is some type, the way you declare a pointer to a single object of type T is
T *p;
and the way you declare a pointer to an array of objects of type T is also
T *p;

Programmers think very differently about a pointer to an object of type T vs. a pointer to an array of objects of type T. But the design of the C language aggressively ignores that difference. In more complicated situations (such as arrays of arrays) the C convention of assuming an outer dimension (whether there or not) is an extra source of confusion.

Quote:
some things work with certain values (numbers) but suddenly are different with other values or in other contexts (arrays, strings)
No, it really all works the same. The second source of confusion is that the language feature of quoted strings and some library function behaviors all create the partial illusion that C has a data type for strings. But actually C has no string data type. It only has arrays of char. An array of char can in many ways be used as if it were a string. But fundamentally it is not a string. The illusion (that it is a string) frays around the edges in many different ways.

Experienced C programmers know that a "C string" is really just an array of characters and know when you can treat it as if it were a real string and when you can't.

Quote:
Code:
    double *dPtr;
    dPtr = (double *)malloc(sizeof(double));
    *dPtr = 3.14159;
A pointer to a single object of type double. Very simple.

Quote:
Code:
    char *string;
    string = (char *)malloc(30 * sizeof(char));
A pointer to an array of objects of type char, with the intent of pretending it is a pointer to a single object of type string.

Quote:
Code:
   scanf(" %s", string);
A call to a library function that supports the illusion that an array of char is a string.

You didn't try
Code:
    *string = "Hello, my name is Johnny";
(which shouldn't compile) which would be continuing to pretend you have a pointer to an object of type string (in a way that fails because there is no type string), conceptually similar to your
Code:
*dPtr = 3.14159;
Instead, you tried
Quote:
Code:
    string = "Hello, my name is Johnny";
But that assignment clearly changes the pointer itself, not the thing pointed to. The most basic understanding of C pointers should cover that distinction.

Finally:
Quote:
Code:
    strcpy(string, "Helly, my name is Johnny");
Another call to a library function that supports the illusion that there is a string type.

Last edited by johnsfine; 11-13-2012 at 12:59 PM.
 
Old 11-14-2012, 04:10 AM   #6
rm_-rf_windows
Member
 
Registered: Jun 2007
Location: Europe
Distribution: Ubuntu
Posts: 292

Original Poster
Rep: Reputation: 27
Many thanks for your detailed explanations johnsfine! Thanks too to all who have replied, for your enthusiasm.

I'm going to try to sum all of this up with a few examples. Please correct me if I'm wrong in what follows, it is also an opportunity to check to see if I've understood. This might also be useful to others struggling with c pointers...

Example 1: The following works!
Code:
    char *string = "Hello, my name is Johnny";
    // OR EQUIVALENT: char string[] = "Hello, my name is Johnny";
    // OR THIS WORKS TOO: char string[100] = "Hello, my name is Johnny";
    printf("The value of 'string' is %s\n", string);
    // never use 'free(string)';
Example 2: The following works!
Code:
    char *string; // DOES NOT WORK WITH 'char string;', in which string is not a string, but rather a character!
    string = "Hello, my name is Johnny"; // DOES NOT WORK WITH: *string = "Hello...";
    printf("The value of 'string' is %s\n", string);
    // never use 'free(string)';
Example 3: An actual pointer to a real char (a single character)
Code:
    char *cPtr;
    cPtr = (char *)malloc(sizeof(char));
    *cPtr = 'c';
    printf("cPtr points to the heap at value '%c'.\n", *cPtr);
    free(cPtr);
Example 4: The exact equivalent of Example 3, but using a double instead of a char
Code:
    double *dPtr;
    dPtr = (double *)malloc(sizeof(double));
    *dPtr = 3.14159;
    printf("dPtr points to the heap at value %f.\n", *dPtr);
    free(dPtr);
In Examples 1 & 2, we are not dealing with actual pointers to a character, but rather special c implementations allowing for the manipulation of strings, which are really arrays of characters. To master this, one must simply remember the proper syntax. Such arrays can be filled with functions of the string.h/string.c library, by assigning values one at a time to each element of such arrays, or by declaring and assigning at the same time (Example 1) or separately observing the exact syntax of Example 2. One never uses free(variable) in such cases. (Question: how is memory freed in this case?)

Example 3 is an actual pointer to an actual char, i.e., one character, and the syntax is exactly like any other pointer towards a single value (compare Example 4, which is identical, but uses a double instead of a char). free(variable) must be used to free up memory.

So the tricky part is sussing out the difference between Example 2 and Example 3, which are extremely similar in appearance but which are actually completely different, the former being a string, the latter a character. For those having a hard time, study Examples 2 & 3 very carefully.

Is what I've said right? Have I forgotten any other possibilities?

Many thanks to all.

rm
 
Old 11-14-2012, 05:06 AM   #7
millgates
Member
 
Registered: Feb 2009
Location: 192.168.x.x
Distribution: Slackware
Posts: 852

Rep: Reputation: 389Reputation: 389Reputation: 389Reputation: 389
Quote:
Originally Posted by rm_-rf_windows View Post
In Examples 1 & 2, we are not dealing with actual pointers to a character
char *ptr is allways (formally) a pointer to character. The difference is only in where it points.

Code:
char *ptr = (char*)malloc(N * sizeof(char))
In this case, you dynamically allocate memory on heap at run-time and make the pointer point to it.


Code:
char *ptr = "Hello!\n"
Here, you make the pointer point to the literal string "Hello\n" which was created at compile-time and is hidden in the executable.


Code:
char c = 'H';
char *ptr = &c
Here, you make the pointer point to an address of the char c, which (depending on where and how it was declared) may be for example on the stack.

Pointers are just variables that store certain "points of interest" in the memory. A pointer to an array is in fact a pointer to the first element of that array (therefore, a pointer to a char in this case). So, for example ptr[3] would be "a character 3 characters after the character pointed to by ptr". Actually, you can dereference it as
Code:
*(ptr+3)
So, we could say (at a low level) a pointer to char allways points to one character. It's up to the programmer to remember that that particular character is followed by several others. So, on a low level, for a compiler, there is no qualitative difference between a pointer to one char and a pointer to an array.
Alternatively, you may think of a character as of an array of size 1. So,
Code:
char c='H';
char *ptr = &c;
printf("%c\n", ptr[0]);
is also valid. The different syntax you use does not mean those are different things internally. It is there just for the programmer's convenience to make the code more readable.

Quote:
Originally Posted by rm_-rf_windows View Post
One never uses free(variable) in such cases. (Question: how is memory freed in this case?)
You don't. The memory was not dynamically allocated on the heap, so you don't free it. The rule of thumb is: if you use malloc(), you should use free(). In an ideal case, think of the malloc and free as of some sort of "curly braces" in your program that define the scope of existence of your variable just as the braces define the scope of existence of your local variables. Each malloc() should be matched in the flow of the program by a corresponding free().

Ok, I hope I didn't confuse you too much.
Have a nice day

Last edited by millgates; 11-14-2012 at 05:09 AM.
 
Old 11-14-2012, 06:06 AM   #8
rm_-rf_windows
Member
 
Registered: Jun 2007
Location: Europe
Distribution: Ubuntu
Posts: 292

Original Poster
Rep: Reputation: 27
Thanks for your reply millgates!

Most of the points you mentioned were familiar to me, but it is true that I don't quite have them down pat yet.

In what follows, once again, I'm going to try to say what is true, if I'm wrong, please correct me, as in my last post. I'm just rehashing this in different ways, from different angles, to try to understand. I'm hoping that this post may be useful to others learning C as well, especially beginners.

I guess one thing that I didn't realize is that "pointer" does not necessarily mean "memory allocation". Pointer or no pointer, memory is allocated either dynamically or statically. Does "*" imply a pointer? If so, the beginner will be confused when dealing with strings and characters...

Code:
char c = 'c'; 
char *pC = &c;
With char c = 'c', memory is allocated and its address can be obtained via &c and a pointer can be created to point to this address, in which case if c is modified, so will *pC given that they point to the same address. Okay.

In the following example:
Code:
char *string; 
string = "Hello, my name is Johnny"; 
printf("The value of 'string' is %s\n", string);
... there is a star or asterisk (*). From my understanding of this, the use of strings in C is the only time where you would use a star and not use malloc() and free(). Is that right? And would 'string' be considered a pointer? Does "*" = pointer, necessarily?

I suppose that another way of thinking of this would be that the equivalent of Java's...
Code:
String s; 
s = "Hello";
...is c's:
Code:
char *s; 
s = "Hello";
Can anybody think of another example where '*' is used but where memory is not allocated dynamically using malloc() and free() other than pointing to a previously declared non-pointer variable)? If not, for new learners, I think this is the source of the confusion. Once you've programmed in C for several years, you do not realize this ambiguity (or is it just me!?)... :-)

This works:
Code:
char *string; 
string = "Hello, my name is Johnny"; 
printf("The first letter of 'string' is '%c'\n", string[0]);
These do NOT work:
Code:
char *c; 
c = 'H'; 
printf("The character 'c' is '%c'\n", c);
Code:
char *c; 
*c = 'H'; 
printf("The character 'c' is '%c'\n", *c);
I'll bet there is now way to get the last two examples to work without malloc() and free() and without getting a pointer to point to a previously declared and assigned pointer or non-pointer variable. Is this the case?

Thanks for all of your response man! Slowly but surely, it will eventually sink in!

rm
 
Old 11-14-2012, 06:18 AM   #9
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 21,838

Rep: Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308
if you really want to say thanks, please press yes (bottom right corner of the post)

Code:
char c = 'H'; 
printf("The character 'c' is '%c'\n", c);
and
Code:
char a = 'H';
char *c = &a;
printf("The character 'c' is '%c'\n", *c);
would work
 
Old 11-14-2012, 08:10 AM   #10
johnsfine
LQ Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,286

Rep: Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197
Quote:
Originally Posted by rm_-rf_windows View Post
Code:
char c = 'c'; 
char *pC = &c;
With char c = 'c', memory is allocated and its address can be obtained via &c and a pointer can be created to point to this address, in which case if c is modified, so will *pC given that they point to the same address.
You just demonstrated that you understand the same concept that later in the same post you indicated you don't understand:

Quote:
From my understanding of this, the use of strings in C is the only time where you would use a star and not use malloc() and free(). Is that right?
Obviously false. You use a star whenever you declare or dereference a pointer. You already demonstrated that you understand you can declare and deference a pointer without involving malloc or free, and you demonstrated that with a char, not a string. You must understand the same would apply to an int or a double or a struct or whatever.

Quote:
And would 'string' be considered a pointer?
In C, the run time value of an array name is just the address of the array (nothing about its size or contents). As I said before, there is no such thing as a "string" in C, there are just a few language features and library routines that pretend an array of char is a string. Really it is just an array of char.

Combining the above to concepts, we get the fact that the run time value of a "string" is the address of the char array.

Next, it would help to understand the relationship between an address and a pointer. If you have already learned about enums in C, an analogy to the relationship between enum constants and int variables might help you understand the relationship between addresses and pointers.

Code:
int V=3;
enum {C=3};
In this code V is a variable that happens at the moment to have the value 3. But C is effectively a constant 3. If you use them in expressions, they are both equally 3. But used in other ways, the difference between variable and non variable will matter.

Now addresses vs. pointers:
Code:
int A[6];
int* P = A;
char *P2 = "some text";
The name A (in most kinds of subsequent use) represents the address of that six element array of integers. The name A is not a pointer, it is just an address.
The name P represents a pointer, which at the moment holds the same address as A. Just as V and C in the previous example have the same value (3) when used in an expression, P and A in this second example have the same value (the address of the array) when used in an expression. And just like V vs. C, P and A differ because P is a pointer (effectively an address variable) while A is an address constant.
Similarly again, we have P2 and "some text" where "some text" in C is an address constant for the place where the compiler put the char array it created to hold that text, and P2 is a pointer (an address variable) whose current value is that same address.

A pointer is a variable. Its value is an address. An array name is not a variable (even though the elements of the array are). In most uses, the value of an array name is an address. Similarly a quoted string is not a variable. It is a non variable whose value (again only in most uses) is an address.

The significant usage in which the "value" of array name or quoted string is not an address is sizeof(), which is a compile time operation that only looks like a function call. In the above example code if we called a function SomeFunction(A) or SomeFunction(P) we would be passing the same address to SomeFunction, because the variable P holds (at the moment) the same value as the constant A. But if we tried sizeof(P) that is very different from sizeof(A) because sizeof is a compile time operation and not a function call.

Quote:
I'll bet there is now way to get the last two examples to work without malloc() and free() and without getting a pointer to point to a previously declared and assigned pointer or non-pointer variable. Is this the case?
If I understand what you mean, then definitely not. A pointer is a variable whose value is an address. Any use of the object pointed to must use a valid address and you only get a valid address from something that has been allocated: statically or on the stack or dynamically.

It is a very common beginner error in C to expect a pointer can be used somehow to store a value of the type pointed to without first storing an address. That is never correct.

Quote:
Originally Posted by millgates View Post
char *ptr is allways (formally) a pointer to character.
From the compiler's point of view, char *ptr declares a variable that holds the address of an array of char's and the compiler has no idea how many char's are in that array.

As programmers we often prefer to think of ptr as holding the address of a char, rather than the address of an array of char. But using that as your main understanding of pointer leads to confusion (such as the OP seems to have over strings) in the cases where a pointer does point to an array. To avoid confusion in the complicated cases, you need to be able to see things from the compiler's point of view. ptr always holds the address of an array of char, but in the common case where the programmer knows it points to a single object, that array (whose size is never known by the compiler) has a size which the programer knows is one.

Last edited by johnsfine; 11-14-2012 at 08:48 AM.
 
Old 11-14-2012, 09:54 AM   #11
theNbomr
LQ 5k Club
 
Registered: Aug 2005
Distribution: OpenSuse, Fedora, Redhat, Debian
Posts: 5,399
Blog Entries: 2

Rep: Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908
I don't know if it helps or confuses, but I always like to make the point that pointers (to any type) always point somewhere. Pointers always point. The art of programming includes making sure that they point somewhere that is both 'legal' and helpful before dereferencing them. And in case that terminology is new, 'dereference' here means to 'access the thing at which the pointer points'. A pointer is a scalar variable which, like all scalars, has a value. Always.

The other explanation of arrays and 'strings' that I think needs emphasis is that an array by name is a form of shorthand that really means 'address-of the first (or should that be "zeroeth"?) element of the array'. I think it is this shorthand which is by far the single most confusing aspect of the C language to newcomers. It is also a quite wonderful form of expression to those who do understand it.

--- rod.

Last edited by theNbomr; 11-14-2012 at 09:59 AM.
 
Old 11-15-2012, 08:35 PM   #12
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 454Reputation: 454Reputation: 454Reputation: 454Reputation: 454
Quote:
Originally Posted by rm_-rf_windows View Post
...
I now realize that those who know how to program in C probably don't realize how complex pointers are in C
...
Consider your computer memory ro be an array of bytes.

Consider pointer to be an index to that array.

That's it - the rest is syntax and understanding how many times you need to dereference pointer in order to access the needed info.

If I'm telling you:

1) go to the table and take there a piece of paper;
2) in that piece of paper find which of the three wardrobes in the room to go to;
3) in the wardrobe pick black sweater

, you have three dereferences to do.

In computer the table, the piece of paper, the wardrobe and the black sweater are all (at) memory locations. So dereferencing is about about index to extract next level index, or finally the needed data.

...

It's a simplified explanation - there can be much more magic to pointers, but it's a good start to grasp the concept.
 
Old 11-17-2012, 02:24 AM   #13
rm_-rf_windows
Member
 
Registered: Jun 2007
Location: Europe
Distribution: Ubuntu
Posts: 292

Original Poster
Rep: Reputation: 27
Many thanks to all who have responded to this post, which has been most interesting.

Originally, my intention in starting this thread was to put myself into the shoes of someone who knew nothing about C, or even nothing about programming, and to try to figure out why this person would have trouble with pointers (or perhaps what I mean is the star (*), the ampersand (&), the absence of them and general syntax).

True, it is important to understand what goes on behind the scenes, but I think I now have some examples to illustrate my point, that is, why the character array poses problems... That is the point, it is the special character array form (C's pseudo-string) that poses a problem (I think! ... we haven't attacked 'char ** c' yet! I propose we do so in a separate post. But for simple pointers, I thought this would be a good way to sum up the thread.).

Now let's just pretend we are showing a beginner how to use a basic pointer by example and without explanation in a similar way in which one would learn a foreign language, without explanation of grammar, by being immersed.

We could show them this, which one could use as a model for every primitive data type in C:

Example 1a:
Code:
    int *iPtr;
    iPtr = (int *)malloc(sizeof(int));
    *iPtr = 25;
    printf("iPtr points to the heap at value '%d'.\n", *iPtr);
    free(iPtr);
Example 1b:
Code:
    char *cPtr;
    cPtr = (char *)malloc(sizeof(char));
    *cPtr = 'H';
    printf("cPtr points to the heap at value '%c'.\n", *cPtr);
    free(cPtr);
etc...

Cool. No exceptions. Always works. The beginner is happy.

Example 2:
Code:
    char *cPtr;
    cPtr = (char *)malloc(sizeof(char)*3);
    cPtr[0] = 'H';
    cPtr[1] = 'i';
    cPtr[2] = '!';
    int i = 0;
    for(i=0; i<3; i++){
        printf("%c ", cPtr[i]);
    }    
    printf("\n");
    free(cPtr);
The beginner tries this same thing with different primitive types and it always works. No exceptions. S/he is very happy (more basic array declarations using square brackets could be taught before this).

And now, the beginner encounters a new example.

Example 3a (THIS WORKS, obvious for us, "obvious" for the beginner):
Code:
char *string;
string = "Hello, my name is Johnny";
printf("The value of 'string' is '%s'\n", string);
Now keep in mind that this is all new to the beginner. It looks familiar to him/her. I've seen this before. Piece of cake! And then... Wait a minute, where's the malloc/free? ... and other questions... He's learning and having trouble sussing out what's what.

The experienced C program insists it is simply an array of chars... So the beginner tries it with other primitive types (after all, the char type is a primitive type and it is "simply" an array) or plays around with it:

Example 3b (DOES NOT WORK, obvious to us, but not to the beginner):
Code:
int *anIntArray;
anIntArray = 34;
printf(... // Not possible !
Example 3c (DOES NOT WORK, obvious to us, but not to the beginner):
Code:
char *string;
string[0] = 'H';
string[1] = 'i';
string[2] = '!';
printf("%s\n", string);
Example 3d (DOES NOT WORK, obvious to us, but not to the beginner):
Code:
char *string;
string[0] = 'H';
string[1] = 'i';
string[2] = '!';
printf("The first letter of 'string' is '%s'\n", string[0]);
Example 3e (DOES NOT WORK, obvious to us, but not to the beginner):
Code:
int *anIntArray2;
anIntArray2[0] = 3477;
anIntArray2[1] = 8722;
anIntArray2[2] = 1;
//printf(... // Not possible !
He then realizes that example 3a is not "simply" an array of chars, but presents a convenient way to manipulate strings in C. Its syntax is specific to a usage. It is an exception to the rule (as in when learning foreign languages).

But before he realizes this, he starts to ask questions (regarding Example 3a):

Why the star in the string declaration (char *string
Why no malloc? Why no free?
Why the double quotes? Why several characters in the double quotes?
Does star (*) imply a pointer?
Does star (*) imply dynamic memory allocation?
Is this the only exception? The char/string type?
(because I'm getting sick and tired of "segmentation fault", compilation and runtime errors!! I'm starting to really hate C!!)

Luckily, the beginner has a wonderful community of programmers of all levels to give him a hand here on LinuxQuestions! :-)

Thanks!

rm

Last edited by rm_-rf_windows; 11-17-2012 at 02:32 AM.
 
Old 11-17-2012, 07:46 AM   #14
johnsfine
LQ Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,286

Rep: Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197
I think you are creating the supposed confusion on purpose by starting with a misleading set of examples. Try starting this way instead:

Basic concept of pointers:

An array name is a constant representing the address of an array. A pointer is a variable holding the address of an array.
Code:
int c[4];
int *p = c;
p[2] = 123;
printf("%d", c[2]);  // c[2] is the same int as p[2]
You can change the address in a pointer. You can't change the address represented by an array name:
Code:
++p;  // now p[0] is the same as c[1], p[1] is c[2], etc.
++c;  // But we can't do this
You can do the above with any data type (in place of int).

One important exception to "An array name is a constant representing the address" is that the compile time operation sizeof() applies to whole arrays. sizeof(c) is the number of bytes required for the 4 integers. sizeof(p) is the number of bytes required for one address.


Alternate syntax

Any address (array name or pointer) can be dereferenced with an alternate syntax:
*c is the same as c[0]
*(c+n) is the same as c[n]

We can create an address (do the reverse of what * did) using &
&*c is back to c
p = &(c[1]); would get us the same address in p that we got earlier with
p = c; followed by ++p;

Dynamic allocation

Instead of pointing at an array declared the usual way, we can use malloc to create a dynamic array and point at it:
Code:
int *p = (int*)( malloc( 4 * sizeof(int) ) );
If you created an array with malloc, you should later free it with free.

Address of a non array

We can set a pointer to the address of a scalar:
Code:
int x;
int *p = &x;
Now p[0] is the same as x, and p[1] is similar to what p[4] would have been in the earlier example, an access past the end of the array.
The compiler doesn't know the length of the array whose address is in the pointer, nor even whether that storage was really declared as an array. When used through a pointer, a scalar is like a one element array.

Initial value of a pointer

If you don't provide an address as the value of a pointer, then the address in that pointer should not be used. If you're lucky, using such an address will seg fault. But it might just trash some other part of your data causing a confusing symptom elsewhere in your program, that is very hard to track back to the bug.

Code:
int *p;
p[0] = 123;  // This 123 might get stored anywhere
C string

Several features of the C language treat a char array as if it were a string. These features are special to char arrays. While everything described above about pointers and arrays applies to pointers and arrays of all types, the special extras for char arrays are only for char arrays.

Code:
char x[] = "text";  // this is a special short hand for
//  char x[] = { 't', 'e', 'x', 't', 0 };
But a quoted string used almost anywhere else in C is an even more special shorthand for the compiler to create a static array of char holding that (null terminated) text and then use the address of that static array in place of the quoted string:

Code:
printf( "Hello world\n" );  // What is actually passed to printf is  the
                            // address of a static array the compiler created

char *t = "text";  // The initial value of t is the address
                   // of a static array the compiler created
Beyond the first parameter of printf being a C string, printf has special support for C strings using %s. It can't do anything similar for arrays of other types.

Other C library functions (such as strcat) also act on addresses of char arrays in ways that no library function acts on arrays of other types (though you could easily write some functions of your own to act on addresses of other data types in similar ways).

That simple
Code:
char *t = "text";
is roughly equivalent to
Code:
static const char CompilerCreatedArray[] = { 't', 'e', 'x', 't', 0 };
char *t = (char*)CompilerCreatedArray;
Notice that we have a const array of characters, but we have used a cast to forget that the characters are const when we assign the address to the pointer.
This is similar to places you might explicitly use a cast to "forget" that something is const. The fact that you have forgotten those chars are const does not mean it is OK to change them. Don't do anything like this:
Code:
char *t = "text";
t[0] = 'T';  // Try to change the first letter to upper case.

Last edited by johnsfine; 11-17-2012 at 01:49 PM. Reason: Misplaced ')'
 
Old 11-17-2012, 11:06 AM   #15
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 454Reputation: 454Reputation: 454Reputation: 454Reputation: 454
Quote:
Originally Posted by rm_-rf_windows View Post
...
Example 3b (DOES NOT WORK, obvious to us, but not to the beginner):
Code:
int *anIntArray;
anIntArray = 34;
printf(... // Not possible !
Example 3c (DOES NOT WORK, obvious to us, but not to the beginner):
...
If you have a CPU/an OS with direct mapping of physical RAM onto logical ones,

Code:
anIntArray = 34;
is quite a legal code, it simply sets pointer to absolute address 34. And that is the way memory mapped registers are accessed, for example.

...

Rather, the code should be written as

Code:
int *anIntArray;
anIntArray = (int *)34;
.
 
  


Reply



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
need help, going mad about array pointers and strings... haydari Programming 1 04-12-2007 06:05 PM
Array of Pointers to C Strings anamericanjoe Programming 7 12-13-2006 06:44 PM
how to find duplicate strings in vertical column of strings markhod Programming 7 11-02-2005 04:04 AM
pointers and strings skibud2 Programming 4 09-22-2003 07:38 AM
C: pointers, strings, splitting headache notsoevil Programming 5 06-19-2003 04:04 PM

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

All times are GMT -5. The time now is 12:37 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