Please explain this issue with array of char pointers.

Discussion in 'C Programming' started by JNLSeb, Jan 23, 2008.

  1. JNLSeb

    JNLSeb Guest

    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!!!
     
    JNLSeb, Jan 23, 2008
    #1
    1. Advertising

  2. JNLSeb

    Guest

    On Jan 23, 2:20 am, "JNLSeb" <> wrote:
    > 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.
     
    , Jan 23, 2008
    #2
    1. Advertising

  3. JNLSeb

    user923005 Guest

    On Jan 22, 4:20 pm, "JNLSeb" <> wrote:
    > 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:
    > ------------
    > 1 - With Sample1, why does the first strcpy work, but the 2nd one cause the
    > fault?


    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!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     
    user923005, Jan 23, 2008
    #3
  4. JNLSeb

    Pedro Graca Guest

    JNLSeb wrote:
    > Here are 2 samples and after the samples are some questions.
    >
    > --------------------------------
    > Sample 1 - Initializes the array
    > --------------------------------
    >
    > #include "stdio.h"

    #include <stdio.h>

    > #include "string.h"

    #include <string.h>

    > #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;
    > }
    >
    >
    > --------------------------------
    > Sample 2 - Does NOT initialize the array

    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:
    > ------------
    > 1 - With Sample1, why does the first strcpy work, but the 2nd one cause the
    > fault?

    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 *
     
    Pedro Graca, Jan 23, 2008
    #4
  5. JNLSeb

    user923005 Guest

    On Jan 22, 5:02 pm, Pedro Graca <> wrote:
    > JNLSeb wrote:
    > > Here are 2 samples and after the samples are some questions.

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

    >
    > > #include "stdio.h"

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

    >
    > #include <string.h>
    >
    > > #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;
    > > }

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

    >
    > 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:
    > > ------------
    > > 1 - With Sample1, why does the first strcpy work, but the 2nd one cause the
    > > fault?

    >
    > 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.
     
    user923005, Jan 23, 2008
    #5
  6. JNLSeb

    Jack Klein Guest

    On Tue, 22 Jan 2008 16:36:39 -0800 (PST), wrote in
    comp.lang.c:

    > On Jan 23, 2:20 am, "JNLSeb" <> wrote:
    > > 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
     
    Jack Klein, Jan 23, 2008
    #6
  7. JNLSeb

    Pedro Graca Guest

    user923005 wrote:
    > 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.
     
    Pedro Graca, Jan 23, 2008
    #7
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. lovecreatesbeauty
    Replies:
    1
    Views:
    1,062
    Ian Collins
    May 9, 2006
  2. Replies:
    3
    Views:
    738
  3. davidb
    Replies:
    0
    Views:
    766
    davidb
    Sep 1, 2006
  4. davidb
    Replies:
    6
    Views:
    1,558
    Default User
    Sep 1, 2006
  5. cerr

    pointers, pointers, pointers...

    cerr, Apr 7, 2011, in forum: C Programming
    Replies:
    12
    Views:
    682
Loading...

Share This Page