GIDForums  

Go Back   GIDForums > Computer Programming Forums > C Programming Language
User Name
Password
Register FAQ Members List Calendar Search Today's Posts Mark Forums Read

 
 
Thread Tools Search this Thread Rate Thread
  #1  
Old 15-Aug-2004, 23:12
nusstu nusstu is offline
New Member
 
Join Date: Mar 2004
Posts: 27
nusstu is on a distinguished road

Why seg fault in char array?


hi,

i just started C and gt a seg fault here:
CPP / C++ / C Code:
char *str = "Hello"; 
*(++str) = 'A';  //I'm trying to change e to A. 
my guess is that it is implicitly converted to constant.

thanks.
  #2  
Old 16-Aug-2004, 07:00
dsmith's Avatar
dsmith dsmith is offline
Senior Member
 
Join Date: Jan 2004
Location: Utah, USA
Posts: 1,351
dsmith is a glorious beacon of lightdsmith is a glorious beacon of lightdsmith is a glorious beacon of lightdsmith is a glorious beacon of lightdsmith is a glorious beacon of light
Hi nusstu.

There are several things wrong with your program. They all have to do with the use of char*. Char* is a an array of chars and is not analogous to a string type in other programming languages.
  1. When you define something a char*, you are actually only allocating memory space for a memory address that will point to a user allocated array of strings. If you are not comfortable with malloc, you should just use a char array:
    CPP / C++ / C Code:
    char str[20];
    
  2. The assignment operator is not valid with a char* type either. If you want to use char*, you must use the strcpy command. If you use the array as above, you can initialize your string as you have done.

  3. This is a dangerous statement whether you use arrays or char*:
    CPP / C++ / C Code:
    *(++str) = 'A';
    
    It will change the e to an A, but it will also change str to point to the next position in the string & therefore if you printed str, you would get Allo. My recomendation, don't ever index the main pointer to a string. Instead use something like:
    CPP / C++ / C Code:
    *(str+1) = 'A'
    
    or
    CPP / C++ / C Code:
    str[1] = 'A';
    

Good luck!
  #3  
Old 16-Aug-2004, 09:03
nusstu nusstu is offline
New Member
 
Join Date: Mar 2004
Posts: 27
nusstu is on a distinguished road
Quote:
Originally Posted by dsmith
Hi nusstu.

There are several things wrong with your program. They all have to do with the use of char*. Char* is a an array of chars and is not analogous to a string type in other programming languages.
[list=1][*]When you define something a char*, you are actually only allocating memory space for a memory address that will point to a user allocated array of strings. If you are not comfortable with malloc, you should just use a char array:
CPP / C++ / C Code:
char str[20];


Hi dsmith,

thanks 4 ur reply.

But, why do we need malloc here? shouldn't char *str="Hello" allocate the space required? You mentioned i can't use the assignment operator with char* is it because C makes it immutable i.e a constant string?

Also, how do we go about assigning an array of int*? I tried, int *a = {1,2};
didn't work?

Thanks.
  #4  
Old 16-Aug-2004, 09:34
dsmith's Avatar
dsmith dsmith is offline
Senior Member
 
Join Date: Jan 2004
Location: Utah, USA
Posts: 1,351
dsmith is a glorious beacon of lightdsmith is a glorious beacon of lightdsmith is a glorious beacon of lightdsmith is a glorious beacon of lightdsmith is a glorious beacon of light
Quote:
Originally Posted by nusstu
Hi dsmith,

thanks 4 ur reply.

But, why do we need malloc here? shouldn't char *str="Hello" allocate the space required?

No. char* != char[]. One is dynamic (run-time) and the other is static (compile time). char* only specifies a location where a memory address will be stored. And at definition this memory address is arbitrary. When you use char* you must allocate the memory dynamically.

CPP / C++ / C Code:
char* str = (char*) malloc(20);
strcpy(str,"hello");


Quote:
Also, how do we go about assigning an array of int*? I tried, int *a = {1,2};
didn't work?

Thanks.

This is the exact same problem. You can not use this type of assignment. Again int* != int[]. One is dynamic and the other is static. You can not assign values to a dynamic structure at initilization.

You can use:
CPP / C++ / C Code:
int a[]={1,2}

or:
CPP / C++ / C Code:
int* a = (int*) malloc(2);

for(int i=0;i<2;i++)
  *(a+i) = i+1;

Hope this helps.
  #5  
Old 16-Aug-2004, 21:11
nusstu nusstu is offline
New Member
 
Join Date: Mar 2004
Posts: 27
nusstu is on a distinguished road
CPP / C++ / C Code:
char* str = (char*) malloc(20);
strcpy(str,"hello");

hm..why do we need to malloc when char* str = "hello"; would do the job? Is it because it becomes a constant string after that, while malloc isn't a constant?

From what i understand, char *str = "hello"; is the same as char str[] = {'h','e',...'\0'}. So why doesn't int *a={1,2}; convert to int a[] = {1,2};?

thanks.
  #6  
Old 17-Aug-2004, 07:27
dsmith's Avatar
dsmith dsmith is offline
Senior Member
 
Join Date: Jan 2004
Location: Utah, USA
Posts: 1,351
dsmith is a glorious beacon of lightdsmith is a glorious beacon of lightdsmith is a glorious beacon of lightdsmith is a glorious beacon of lightdsmith is a glorious beacon of light
Sorry nusstu. I am not doing a very good job of explaining.

Quote:
Originally Posted by nusstu
hm..why do we need to malloc when char* str = "hello"; would do the job?

The answer here is that char* str = "hello" will not do the job.

I am not an expert at this, but here is what happens when you declare the different types.

char str[size]
This is a static definition of an array of characters. It is created in your "program" memory space and is defined at compile time. This is part of the image that is created when your process loads. All of the memory is allocated in this program image and can not be freed or the position of it changed. The only way to create a larger array is to change and recompile your program.

Code:
str --> Address x (in program memory) x --> H E L L O \0

Since all of the memory is allocated at compile time, C allows you to initialize this chunk of memory as well. So in initializations (and only in initializations) we can load this string by using the assignment operator.

char* str
This is a dynamic definition of an array of characters. The only thing that is created in "program" memory is a variable big enough to hold a memory address.

So upon declaring a char* str all we have is:
Code:
str --> Undefined number (don't use yet as this will give seg faults almost assuredly).

So since there is no memory allocated to hold the string at compile time, it is impossible to use the assignment initialization.

Now, when malloc is used memory is allocated from the "heap" and a pointer is returned to this location.
CPP / C++ / C Code:
str = (char*) malloc(len);
Code:
str ---> Address x (in heap memory) x ---> A properly allocated size of memory.

Now this memory can be resized & freed as your program executes. This is run-time allocation as opposed to compile-time allocation.

Now, my question is why do you want to use int* & char*? If you know the size of your array at compile time, just use int[] and char[]. You can do all of the things that you want to do with the pointers, but the memory is allocated at compile time. You don't need to worry about getting heap memory and freeing heap memory. Only use the pointers if it is critical that memory can be allocated at run time.

You can even access the arrays using pointer syntax if you like it better.
CPP / C++ / C Code:
int array[4];

*(array+1) = 10;   //Set the second element of the array to 10.

Or you can make a pointer point to the location of an array.
CPP / C++ / C Code:
char array[]="Hello";
char *parse;

parse = array;
parse++;
*parse = 'E';

I am about out of ideas of how to explain this. The one point I want to make sure that I get across is that a dynamic array is not a static array. When you define a dynamic array there is no memory allocated for it beyond enough to hold the address of where it will point.

HTH,
d
  #7  
Old 18-Aug-2004, 10:52
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 4,720
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold
Quote:
Originally Posted by nusstu
hi,

i just started C and gt a seg fault here:
CPP / C++ / C Code:
char *str = "Hello"; 
*(++str) = 'A';  //I'm trying to change e to A. 
my guess is that it is implicitly converted to constant.

thanks.

You have declared a variable named str to be a (pointer to char). Your declaration also sets the value of str to be the address of the string constant "Hello". Note that there is no such thing as a string data type in C, but there is such a thing as a string constant.

The string constant is located some place in memory where you can read, but you shouldn't attempt to write to it. Normally, of course, you don't have to know what the actual address is, since you will use the variable name to access the contents.

Then you incremented the pointer, so that it points to the second character of the string constant (so far, so good). But then wrote something new to that memory location. You can change the value of str to anything you want, but it is not legal to attempt to change the value of a string constant. In this case, the compiler doesn't keep track of what your assignment statement is doing, even though for this simple program we can tell at a glance what's going on.

The way that you have written the program, there is not any illegal C code here (so no compiler errors), but the attempted activity at run time is bad.


Some compilers actually generate code that lets this program do perform the action that you have indicated here, and some generate an "exception" at run time. When I compiled the code with Borland bcc32 and Microsoft Visual C++ on my Windows XP box, the program ran to completion, and actually changed the string to "HAllo". With gcc, I got a run time error:
Quote:
3 [main] a 1408 handle_exceptions: Exception: STATUS_ACCESS_VIOLATION
862 [main] a 1408 open_stackdumpfile: Dumping stack trace to a.exe.stackdump

Here's the program that I actually ran. Note that I separated the declaration and assignment of str. (This result idendical to that of your example.) I also separated the increment and assignment statement so that you can see exactly where the exception occurred.

CPP / C++ / C Code:
#include <stdio.h>
int main()
{
  char *str; /* define a variable of type (pointer to char)       */

  printf("Initially:   str = %p\n", str);

  /* set the variable str to point to a string constant */
  str = "Hello";

  printf("After <str = \"Hello\";>   str = %p, *str = %c (0x%2x hex)\n", 
          str, *str, *str);
  printf("Heres the string pointed to by str: <%s>\n\n", str);

  /* increment the pointer (That's OK) */
  ++str;

  printf("After ++str: str = %p; *str = %c (0x%02x hex)\n", 
          str, *str, *str);
  printf("Heres the string now pointed to by str: <%s>\n\n", str);

  printf("  NOTE: the next statement is illegally storing a value into\n");
  printf("  memory associated with a string constant. At run time you\n");
  printf("  may see exception here (gcc says STATUS_ACCESS_VIOLATION).\n");
  printf("  The code generated by your compiler may actually do the\n"); 
  printf("  assignment and cheerfully proceed with the rest of the\n");
  printf("  program.\n");
  printf("  But, regardless of the results you get here, this is\n\n");
  printf("             WRONG, WRONG, WRONG!\n\n");

  *str = 'A';

  printf("After *str = 'A': str = %p, *str = %c (0x%02x hex)\n", 
         str, *str, *str);
  printf("Heres the string pointed to by str: <%s>\n", str);
  return 0;
}

Dave
  #8  
Old 18-Aug-2004, 14:13
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 4,720
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold
Quote:
Originally Posted by nusstu

From what i understand, char *str = "hello"; is the same as char str[] = {'h','e','l,l','\0'}

Not true. The first form declares an variable to be a pointer (tells the compiler to allocate memory for a pointer). Then it sets the value of the pointer to be the address of the string constant "hello" (some memory location readable but not writeable by this program).

The second form tells the compiler to allocate storage for six chars and puts the values 'h', 'e', 'l', 'l', 'o', '\0' into those locations. These memory locations are readable and writeable by this program.

Look at the following. Compile and run it. If you don't understand what's happening, you can always ask.

CPP / C++ / C Code:
#include <stdio.h>

void print_stuff1(char *);
void print_stuff2(char []);

int main()
{
  /*
   * The following declars that char_point is a variable of type
   * (pointer to char). The initialization sets the value of char_point
   * to the address of the string constant "Hello, World". The memory
   * where the string constant is stores is accessible (readable)
   * from this program, but the program is not allowed to write to
   * that area.
   */
  char *char_point = "Hello, World";

  /*
   * The following declares that char_array is an array of char. The
   * initialization does two things:
   * 1. Tells the compiler to allocate 3 chars for the array
   * 2. Puts 'H', 'i' and '\0' into three successive char locations,
   *    starting at &char_array[0]
   */
  char char_array[] = "Hi";

  /* 
   * The following declares that ch_array2 is an array of char.
   * The initialization does two things:
   * 1. Tells the compiler to allocate 3 chars for the array
   * 2. Puts the chars 'Y', 'o', and '\0' into three successive char
   *    locations, starting at &ch_array[0]
   */
  char ch_array2[] = {'Y', 'o', '\0'};

  /* The following declares that int_array is an array of int. The
   * initialization does two things:
   * 1. Tells the compiler to allocate two ints for the array
   * 2. Puts ints 1 and 2 into two successive int locations, starting
   *    at &int_array[0]
   */
  int int_array[] = {1, 2};

  /* The following declares that int_point is a variable of type
   * (pointer to int).
   * Now why can't we say something like the following?
    
     int *int_point = {1,2}

   * Because there's no such thing as an int array constant
   */
  int *int_point;

  printf("sizeof(char_point) = %d\n", sizeof(char_point));
  printf("sizeof(char_array) = %d\n", sizeof(char_array));
  
  print_stuff1(char_point);
  print_stuff1(ch_array2);
   
  print_stuff2(char_point);
  print_stuff2(ch_array2);
   
  return 0;
}


void print_stuff1(char *cp)
{
  printf("In print_stuff1: cp = %p, sizeof(cp) = %d, *cp = %c\n", 
          cp, sizeof(cp), *cp);
}

void print_stuff2(char ca[])
{
  printf("In print_stuff2: ca = %p, sizeof(ca) = %d, ca[0] = %c\n",
          ca, sizeof(ca), ca[0]);
}

Regards,

Dave
  #9  
Old 18-Aug-2004, 14:35
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 4,720
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold
Quote:
Originally Posted by nusstu
So why doesn't int *a={1,2}; convert to int a[] = {1,2};?

thanks.

When you write
CPP / C++ / C Code:
char *str = "Hello";

The variable str is declared as a "pointer to char", and its value is set to the address of the string constant "Hello". A string constant is a null-terminated sequence of chars.

There is no corresponding null-terminated sequence of ints, so the notation
CPP / C++ / C Code:
int *a = {1,2};
does not make sense.

whereas
CPP / C++ / C Code:
int a[] = {1,2};

allocates two ints and sets their values to 1 and 2.

Dave

Dave
  #10  
Old 19-Aug-2004, 00:40
WaltP's Avatar
WaltP WaltP is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Midwest US
Posts: 3,245
WaltP is a name known to allWaltP is a name known to allWaltP is a name known to allWaltP is a name known to allWaltP is a name known to allWaltP is a name known to all
Look at it this way.

You live in a house (or something similar). This house has an address. When you tell someone where you live, you give them your address. That address is NOT the house itself, but the location of the house -- it points to the house. The house is the physical location.

char p[6]; defines the house itself. The physical space the house is at. There are no details about the house.

char p[6] = "hello"; defines the house as above, and it's color, style, and other details.

char *p = "hello"; defines the address of the house (*p) and its physical location and details ("hello").

char *p; is a blank page in your address book. It's ready to contain an address, but has not been filled in yet. It points nowhere (or more likely to a bad address that sends you to an empty lot in another state)
__________________

Age is unimportant -- except in cheese
 
 

Recent GIDBlogDeveloping GUIs with wxPython (Part 4) by crystalattice

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Rate This Thread
Rate This Thread:

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

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
2 D char Array gwk C Programming Language 3 20-Jul-2004 13:40
3D array dynamic memory allocation cjwatchdog C Programming Language 3 20-Feb-2004 15:27
(read/write file) newbie need help plz momotx C Programming Language 6 28-Jan-2004 13:40
convert long to pointer to char realpopeye C++ Forum 2 26-Sep-2003 10:22

Network Sites: GIDNetwork · GIDWebHosts · GIDSearch · Learning Journal by J de Silva, The

All times are GMT -6. The time now is 05:28.


vBulletin, Copyright © 2000 - 2008, Jelsoft Enterprises Ltd.