Please explain this issue with array of char pointers.

J

JNLSeb

Here are 2 samples and after the samples are some questions.

--------------------------------
Sample 1 - Initializes the array
--------------------------------

#include "stdio.h"
#include "string.h"
#include "windows.h"
int main(int argc, char **argv) {
char *asArgs[28] = {"ABB", "aaaa"};
int v_i = 0;
for(v_i=0; v_i < 27; ++v_i){
asArgs[v_i] = malloc(100);
memset(asArgs[v_i], '\0', 100);
}
strcpy(asArgs[25], "P");
asArgs[25] = "P";
asArgs[25] ="";
asArgs[25] ="A";
strcpy(asArgs[25], "P"); //*******Will cause Fault on this 2nd call
to the string copy command.
return 0;
}


--------------------------------
Sample 2 - Does NOT initialize the array
--------------------------------

#include "stdio.h"
#include "string.h"
#include "windows.h"
int main(int argc, char **argv) {
char *asArgs[28] = {"ABB", "aaaa"};
int v_i = 0;

strcpy(asArgs[25], "P"); //******Will cause Fault on this 1st call
to the string copy command.
//*******The following commands all work.
asArgs[25] = "P";
asArgs[25] ="";
asArgs[25] ="A";
return 0;
}

Questions:
------------
1 - With Sample1, why does the first strcpy work, but the 2nd one cause the
fault?
2 - With Sample2, why does the strcpy fail?
3 - With Sample2, why can the asArgs elements be assigned values directly
when the array elements are not allocated?
4 - Is there a "proper" way to assign values to the elements of a char
array?

TIA!!!
 
V

vippstar

Here are 2 samples and after the samples are some questions.

--------------------------------
Sample 1 - Initializes the array
--------------------------------

#include "stdio.h"
#include "string.h"
#include "windows.h"
int main(int argc, char **argv) {
char *asArgs[28] = {"ABB", "aaaa"};
int v_i = 0;
for(v_i=0; v_i < 27; ++v_i){
asArgs[v_i] = malloc(100);
memset(asArgs[v_i], '\0', 100);
}
strcpy(asArgs[25], "P");
asArgs[25] = "P";
asArgs[25] ="";
asArgs[25] ="A"; /* here's your mistake, point to string literal */
strcpy(asArgs[25], "P");
An awful lot of mistakes in your code, segfault is because you write
to a string literal which is pointed to by asArgs[25].
string literals are const. you cannot write over them, except if you
enable some compiler extension. (nothing to do with ISO C after that)
--------------------------------
Sample 2 - Does NOT initialize the array
--------------------------------

#include "stdio.h"
#include "string.h"
#include "windows.h"
int main(int argc, char **argv) {
char *asArgs[28] = {"ABB", "aaaa"};
int v_i = 0;

strcpy(asArgs[25], "P"); //******Will cause Fault on this 1st call
to the string copy command.
Because you write to NULL.
When you initialize the array of pointers asArgs you initialize only
the first two elements, and the rest are 0'ed or NULL'ed.
asArgs[25] evaluates to NULL.
//*******The following commands all work.
asArgs[25] = "P";
asArgs[25] ="";
asArgs[25] ="A";
These are not commands.
 
U

user923005

Here are 2 samples and after the samples are some questions.

--------------------------------
Sample 1 - Initializes the array
--------------------------------

#include "stdio.h"
#include "string.h"
#include "windows.h"
int main(int argc, char **argv) {
    char *asArgs[28] =  {"ABB", "aaaa"};
    int v_i = 0;
    for(v_i=0; v_i < 27; ++v_i){
       asArgs[v_i] = malloc(100);
       memset(asArgs[v_i], '\0', 100);
    }
        strcpy(asArgs[25], "P");
        asArgs[25] = "P";
        asArgs[25] ="";
        asArgs[25] ="A";
        strcpy(asArgs[25], "P");  //*******Will cause Fault on this 2nd call
to the string copy command.
return 0;

}

--------------------------------
Sample 2 - Does NOT initialize the array
--------------------------------

#include "stdio.h"
#include "string.h"
#include "windows.h"
int main(int argc, char **argv) {
    char *asArgs[28] =  {"ABB", "aaaa"};
    int v_i = 0;

        strcpy(asArgs[25], "P"); //******Will cause Fault on this 1st call
to the string copy command.
       //*******The following commands all work.
        asArgs[25] = "P";
        asArgs[25] ="";
        asArgs[25] ="A";
return 0;

}

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

int main0 (int argc, char **argv)
{
char *asArgs[28] =
{"ABB", "aaaa"};
int v_i = 0;
for (v_i = 0; v_i < 27; ++v_i)
{
asArgs[v_i] = malloc (100);
memset (asArgs[v_i], '\0', 100);
}
strcpy (asArgs[25], "P");
asArgs[25] = "P";
asArgs[25] = "";
asArgs[25] = "A";
strcpy (asArgs[25], "P"); /* Fault on 2nd call to strcpy function.
*/
return 0;

}

int main1 (int argc, char **argv)
{
char *asArgs[28] =
{"ABB", "aaaa"};
int v_i = 0;


strcpy (asArgs[25], "P"); /* Fault on 1st call to strcpy function */
asArgs[25] = "P";
asArgs[25] = "";
asArgs[25] = "A";
return 0;

}

int main (int argc, char **argv)
{
main0 (argc, argv);
main1 (argc, argv);
return 0;
}

/*
C:\tmp>splint foo.c
Splint 3.1.1 --- 12 Mar 2007

foo.c: (in function main0)
foo.c(8,3): Initializer block for asArgs has 2 elements, but declared
as char *
[28]: "ABB", "aaaa"
Initializer does not define all elements of a declared array. (Use
-initallelements to inhibit warning)
foo.c(13,28): Function memset expects arg 2 to be int gets char: '\0'
A character constant is used as an int. Use +charintliteral to allow
character constants to be used as ints. (This is safe since the
actual type
of a char constant is int.)
foo.c(13,15): Possibly null storage asArgs[] passed as non-null param:
memset (asArgs[v_i], ...)
A possibly null pointer is passed as a parameter corresponding to a
formal
parameter with no /*@null@*/ annotation. If NULL may be used for
this
parameter, add a /*@null@*/ annotation to the function parameter
declaration.
(Use -nullpass to inhibit warning)
foo.c(12,21): Storage asArgs[] may become null
foo.c(16,3): Observer storage assigned to unqualified reference:
asArgs[25] = "P"
Observer storage is transferred to a non-observer reference. (Use
-observertrans to inhibit warning)
foo.c(16,16): Storage becomes observer
foo.c(17,3): Observer storage assigned to unqualified reference:
asArgs[25] = ""
foo.c(17,16): Storage becomes observer
foo.c(18,3): Observer storage assigned to unqualified reference:
asArgs[25] = "A"
foo.c(18,16): Storage becomes observer
foo.c(5,16): Parameter argc not used
A function parameter is not used in the body of the function. If the
argument
is needed for type compatibility or future plans, use /*@unused@*/
in the
argument declaration. (Use -paramuse to inhibit warning)
foo.c(5,29): Parameter argv not used
foo.c: (in function main1)
foo.c(27,3): Initializer block for asArgs has 2 elements, but declared
as char
* [28]: "ABB", "aaaa"
foo.c(32,3): Observer storage assigned to unqualified reference:
asArgs[25] = "P"
foo.c(32,16): Storage becomes observer
foo.c(33,3): Observer storage assigned to unqualified reference:
asArgs[25] = ""
foo.c(33,16): Storage becomes observer
foo.c(34,3): Observer storage assigned to unqualified reference:
asArgs[25] = "A"
foo.c(34,16): Storage becomes observer
foo.c(28,7): Variable v_i declared but not used
A variable is declared but never used. Use /*@unused@*/ in front of
declaration to suppress message. (Use -varuse to inhibit warning)
foo.c(24,16): Parameter argc not used
foo.c(24,29): Parameter argv not used
foo.c: (in function main)
foo.c(41,3): Return value (type int) ignored: main0(argc, argv)
Result returned by function call is not used. If this is intended,
can cast
result to (void) to eliminate message. (Use -retvalint to inhibit
warning)
foo.c(42,3): Return value (type int) ignored: main1(argc, argv)
foo.c(5,5): Function exported but not used outside foo: main0
A declaration is exported, but not used outside this module.
Declaration can
use static qualifier. (Use -exportlocal to inhibit warning)
foo.c(22,1): Definition of main0
foo.c(24,5): Function exported but not used outside foo: main1
foo.c(37,1): Definition of main1

Finished checking --- 19 code warnings
*/
Questions:

What do you think?
2 - With Sample2, why does the strcpy fail?

What do you think and why?
3 - With Sample2, why can the asArgs elements be assigned values directly
when the array elements are not allocated?

Tell me what you think about it?
4 - Is there a "proper" way to assign values to the elements of a char
array?
Yes.

TIA!!!

WIA!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 
P

Pedro Graca

JNLSeb said:
Here are 2 samples and after the samples are some questions.
#include said:
#include "string.h"
#include said:
#include "windows.h"
Ok, I guess :)
int main(int argc, char **argv) {
char *asArgs[28] = {"ABB", "aaaa"};
Declare and initialize an array of 28 char *.
The first element of the array points to the string "ABB",
the 2nd element points to the string "aaaa".
(Note this strings can be anywhere inside your computer --
particularly they do not *need* to be in memory you can write to)
The other 26 elements are initialized to NULL.
int v_i = 0;
for(v_i=0; v_i < 27; ++v_i){
asArgs[v_i] = malloc(100);
You just "lost" the addresses of the strings "ABB" and "aaaa"!
memset(asArgs[v_i], '\0', 100);
}
Almost all array elements now point to some chunk of memory that
belongs to them. You can read from and write to that memory. Array
element asArgs[27] is still NULL.
strcpy(asArgs[25], "P");
Ok. Copy 2 bytes ('P' and the string terminator) to asArgs[25].
asArgs[25] = "P";
You've just lost the memory chunk assigned to asArgs[25].
You also made the pointer point to the string "P" somewhere inside
your computer.
This somewhere isn't necessarily a place you can write to!
asArgs[25] ="";
Same as above (except for losing the memory chunk).
asArgs[25] ="A";
Same as above.
strcpy(asArgs[25], "P"); //*******Will cause Fault on this 2nd call
to the string copy command.
Now you try to write 2 bytes ('P' and the string terminator) to the
address of that last "A".
You do not own that address. For instance, it can be in ROM.
(Oh! and // comments tend to break the code when posted to Usenet)
return 0;
}
Oh, yes it does!
--------------------------------

#include "stdio.h"
#include "string.h"
#include "windows.h"
int main(int argc, char **argv) {
char *asArgs[28] = {"ABB", "aaaa"};
Initialize the array with 26 NULL pointers!
int v_i = 0;

strcpy(asArgs[25], "P"); //******Will cause Fault on this 1st call
to the string copy command.
Trying to write to a NULL pointer, usually causes Faults!
//*******The following commands all work.
asArgs[25] = "P";
asArgs[25] ="";
asArgs[25] ="A";
return 0;
}

Questions:
Because the address pointed to on the first strcpy() is part of memory
you "own"; on the second copy it isn't.
2 - With Sample2, why does the strcpy fail?
Because you're trying to write to a NULL pointer.
3 - With Sample2, why can the asArgs elements be assigned values directly
when the array elements are not allocated?
each of the asArgs elements is a pointer
asArgs[23] is a char *
You cannot put a letter into a char *, but you can put the address of
a string containing a letter there.

char *pointer;
pointer = "P"; /* ok, but pointer points to memory you do not "own" */
pointer = 'P'; /* invalid -- cannot assign a character to a pointer */
4 - Is there a "proper" way to assign values to the elements of a char
array?
Yes :)
But you do not have a char array in the example you posted -- you have
an array of char *
 
U

user923005

JNLSeb said:
Here are 2 samples and after the samples are some questions.
#include "stdio.h"

#include said:
#include "string.h"

#include said:
#include "windows.h"

Ok, I guess :)
int main(int argc, char **argv) {
    char *asArgs[28] =  {"ABB", "aaaa"};

Declare and initialize an array of 28 char *.
The first element of the array points to the string "ABB",
the 2nd element points to the string "aaaa".
(Note this strings can be anywhere inside your computer --
particularly they do not *need* to be in memory you can write to)
The other 26 elements are initialized to NULL.
    int v_i = 0;
    for(v_i=0; v_i < 27; ++v_i){
       asArgs[v_i] = malloc(100);

You just "lost" the addresses of the strings "ABB" and "aaaa"!
       memset(asArgs[v_i], '\0', 100);
    }

Almost all array elements now point to some chunk of memory that
belongs to them. You can read from and write to that memory. Array
element asArgs[27] is still NULL.>         strcpy(asArgs[25], "P");

Ok. Copy 2 bytes ('P' and the string terminator) to asArgs[25].
        asArgs[25] = "P";

You've just lost the memory chunk assigned to asArgs[25].
You also made the pointer point to the string "P" somewhere inside
your computer.
This somewhere isn't necessarily a place you can write to!
        asArgs[25] ="";

Same as above (except for losing the memory chunk).
        asArgs[25] ="A";

Same as above.
        strcpy(asArgs[25], "P");  //*******Will cause Fault on this 2nd call
to the string copy command.

Now you try to write 2 bytes ('P' and the string terminator) to the
address of that last "A".
You do not own that address. For instance, it can be in ROM.
(Oh! and // comments tend to break the code when posted to Usenet)
return 0;
}

Oh, yes it does!
--------------------------------
#include "stdio.h"
#include "string.h"
#include "windows.h"
int main(int argc, char **argv) {
    char *asArgs[28] =  {"ABB", "aaaa"};

Initialize the array with 26 NULL pointers!
    int v_i = 0;
        strcpy(asArgs[25], "P"); //******Will cause Fault on this 1st call
to the string copy command.

Trying to write to a NULL pointer, usually causes Faults!
       //*******The following commands all work.
        asArgs[25] = "P";
        asArgs[25] ="";
        asArgs[25] ="A";
return 0;
}
Questions:

Because the address pointed to on the first strcpy() is part of memory
you "own"; on the second copy it isn't.
2 - With Sample2, why does the strcpy fail?

Because you're trying to write to a NULL pointer.
3 - With Sample2, why can the asArgs elements be assigned values directly
when the array elements are not allocated?

each of the asArgs elements is a pointer
asArgs[23] is a char *
You cannot put a letter into a char *, but you can put the address of
a string containing a letter there.

char *pointer;
pointer = "P"; /* ok, but pointer points to memory you do not "own" */
pointer = 'P'; /* invalid -- cannot assign a character to a pointer */
4 - Is there a "proper" way to assign values to the elements of a char
array?

Yes :)
But you do not have a char array in the example you posted -- you have
an array of char *

Are you really incapable of recognizing a homework problem?

You have done him a terrible disservice by feeding him the answers on
a plate instead of letting _him_ figure out *why* the problems were
symptoms of various mistakes.
 
J

Jack Klein

Here are 2 samples and after the samples are some questions.

--------------------------------
Sample 1 - Initializes the array
--------------------------------

#include "stdio.h"
#include "string.h"
#include "windows.h"
int main(int argc, char **argv) {
char *asArgs[28] = {"ABB", "aaaa"};
int v_i = 0;
for(v_i=0; v_i < 27; ++v_i){
asArgs[v_i] = malloc(100);
memset(asArgs[v_i], '\0', 100);
}
strcpy(asArgs[25], "P");
asArgs[25] = "P";
asArgs[25] ="";
asArgs[25] ="A"; /* here's your mistake, point to string literal */
strcpy(asArgs[25], "P");
An awful lot of mistakes in your code, segfault is because you write
to a string literal which is pointed to by asArgs[25].
string literals are const. you cannot write over them, except if you
enable some compiler extension. (nothing to do with ISO C after that)

String literals in C have the type "array of char", and they do most
specifically do not have the type "array of const char".

Attempting to modify a string literal in C is undefined behavior
because the C standard specifically states that it is, not because
they have the type qualifier "const".

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
 
P

Pedro Graca

user923005 said:
Are you really incapable of recognizing a homework problem?
I must have been more tired than I thought.
You have done him a terrible disservice by feeding him the answers on
a plate instead of letting _him_ figure out *why* the problems were
symptoms of various mistakes.
I'd like to offer my apologies to JNLSeb and extend them to the C
community.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,045
Latest member
DRCM

Latest Threads

Top