My understanding:
char * c means c is pointing nothing.
When I type "Hello World", c is now pointing the first address of "Hello World".
It should print H and e, but I got "Segmentation fault: 11" error.
Can anyone please enlighten me why and how char * c = NULL; is causing an error?
Thanks in advance!
#include <stdio.h>
int main(void)
{
char * c = NULL;
gets(c);
printf("%c, %c\n", c[0], c[1]);
return 0;
}
gets doesn't allocate memory. Your pointer is pointing to NULL, which cannot be written to, so when gets tries to write the first character there, you seg fault.
The solution is:
Use a stack or global array (char c[1000];) or a pointer to dynamically allocated memory (char *c = malloc(1000);), not a NULL pointer.
Never use gets, which is intrinsically broken/insecure (it can't limit the read to match the size of the available buffer); use fgets instead.
char *c = NULL; declares the pointer c initialized to NULL. It is a pointer to nowhere.
Recall, A pointer is just a variable that holds the address to something else as its value. Where you normally think of a variable holding an immediate values, such as int a = 5;, a pointer would simply hold the address where 5 is stored in memory, e.g. int *b = &a;. Before you can use a pointer to cause data to be stored in memory -- the pointer must hold the address for (e.g. it must point to) the beginning of a valid block of memory that you have access to.
You can either provide that valid block of memory by assigning the address of an array to your pointer (where the pointer points to where the array is stored on the stack), or you can allocate a block of memory (using malloc, calloc or realloc) and assign the beginning address for that block to your pointer. (don't forget to free() what you allocate).
The simplest way is to declare a character array and then assign the address to the first element to your pointer (an array is converted to a pointer to the first element on access, so simply assigning the character array to your pointer is fine). For example with the array buf providing the storage and the pointer p holding the address of the first character in buf, you could do:
#include <stdio.h>
#include <string.h> /* for strcspn & strlen */
#define MAXC 1024 /* if you need a constant, #define one (or more) */
int main (void)
{
char buf[MAXC], /* an array of MAXC chars */
*p = buf; /* a pointer to buf */
if (fgets (p, MAXC, stdin)) { /* read line from stdin */
p[strcspn (p, "\n")] = 0; /* trim \n by overwriting with 0 */
if (strlen (p) > 1) { /* validate at least 2-chars */
printf("%c, %c\n", p[0], p[1]); /* output them */
}
}
return 0;
}
(note: strcspn above simply returns the number of character in your string up to the '\n' character allowing you to simply overwrite the '\n' included by fgets() with '\0' -- which is numerically equivalent to 0)
Example Use/Output
$ ./bin/fgetsmin
Hello
H, e
Look things over and let me know if you have further questions.
Related
Can someone explain to me why my call to malloc with a string size of 6 returns a sizeof of 4 bytes? In fact, any integer argument I give malloc I get a sizeof of 4. Next, I am trying to copy two strings. Why is my ouput of the copied string (NULL)?
Following is my code:
int main()
{
char * str = "string";
char * copy = malloc(sizeof(str) + 1);
printf("bytes allocated for copy: %d\n", sizeof(copy));
while(*str != '\0'){
*copy = *str;
str++;
copy++;
}
copy = '\0';
printf("%s\n", copy);
}
sizeof(str) returns the size of a pointer of type char*. What you should do is to malloc the size of the string it self:
char * copy = malloc(strlen(str) + 1);
Also, these lines:
while(*str != '\0'){
*copy = *str;
str++;
copy++;
}
copy = '\0';
Can be rewritten easily in C like this:
while(*copy++ = *str++);
First you should understand that sizeof(xxx) where xxx is any left value expression (a variable) is always equivalent to do sizeof(type of xxx). Hence what is really doing your sizeof(str) is returning the size of a char *, that is the size of any other pointer. On a 32 bits architecture you'll get 4, on a 64 bits architecture it'll be 8, etc.
So, as others also explained you have to know the length of the string you want to allocate, and then add 1 to store the terminal \0, C implicitly use to put at the end of strings.
But to do what you want (copy a string and allocate necessary space) it will be more simple and more efficient to use strdup, that does exactly that : a malloc and a strcopy.
You should also not forget to free space you allocated yourself (using malloc, calloc, strdup or any other allocation function). In C it won't go away when allocated variable go out of scope. It will stay used until the end of the program. That's what you call a memory leak.
#include <string.h> /* for strdup, strlen */
#include <stdio.h> /* for printf */
int main()
{
char * str = "string";
char * copy = strdup(str);
printf("bytes at least allocated for copy: %d\n", strlen(copy)+1);
printf("%s\n", copy);
free(copy);
}
One last point : I changed message to bytes at least allocated because you don't really know the size allocated when calling malloc. It quite often allocates a slighly more space that what you asked for. One reason is that in many memory managers free blocks are linked together using some hidden data structure and any allocated block should be able to contain at least such structure, another is that allocated blocks are always aligned in such a way to be compatible with any type alignment.
Hope it will help you to understand C a little better.
You're getting the size of the str pointer (4 bytes), not what it's pointing to?
sizeof(str) returns the space necessary to store the pointer to the string, not the string itself. You can see the size of the string with strlen(str) for example.
Then you affect your copy pointer to an integer which has the value 0 (the character '\0'). It is the same as copy = NULL, which is what the printf() function shows you.
sizeof() returns the size of the actual type of the variable. So, when you define your type as char *, it returns the size of a pointer.
But if you made your variable an array, sizeof would return the size of the array itself, which would do what you want to do:
char *ptr = "moo to you";
char arr[] = "moo to you";
assert(sizeof(ptr) == 4); // assuming 32 bit
assert(sizeof(arr) == 11); // sizeof array includes terminating NUL
assert(strlen(arr) == 10); // strlen does not include terminating NUL
To tackle your second questions, by executing the statement copy++ you have changed the value of copy (that is, the address in memory that holds a char array) so that by the time you print it out, it is pointing at the end of the array rather than the beginning (the value returned by malloc()). You will need an extra variable to update the string and be able to access the beginning of the string:
Edit to repair malloc/sizeof issue - thanks CL.
char * str = "string";
/* char * copy = malloc(sizeof(str) + 1); Oops */
char * copy = malloc(strlen(str) + 1);
char * original_copy = copy;
printf("bytes allocated for copy: %d\n", sizeof(copy));
while(*str != '\0'){
*copy = *str;
str++;
copy++;
}
copy = '\0';
printf("%s\n", original_copy);
sizeof() returns you the size of the pointer and not the amount of allocated bytes. You don't need to count the allocated bytes, just check if the returned pointer is not NULL.
The line copy = '\0'; resets the pointer and makes it NULL.
You can use:
size_t malloc_usable_size (void *ptr);
instead of : sizeof
But it returns the real size of the allocated memory block! Not the size you passed to malloc!
When we allocating memory spaces for a string, do the following 2 ways give the same result?
char *s = "abc";
char *st1 = (char *)malloc(sizeof(char)*strlen(s));
char *st2 = (char *)malloc(sizeof(s));
In other words, does allocate the memory based on the size of its characters give the same result as allocating based on the size of the whole string?
If I do use the later method, is it still possible for me to add to that memory spaces character by character such as:
*st = 'a';
st++;
*st = 'b';
or do I have to add a whole string at once now?
Let's see if we can't get you straightened out on your question and on allocating (and reallocating) storage. To begin, when you declare:
char *s = "abc";
You have declared a pointer to char s and you have assigned the starting address for the String Literal "abc" to the pointer s. Whenever you attempt to use sizeof() on a_pointer, you get sizeof(a_pointer) which is typically 8-bytes on x86_64 (or 4-bytes on x86, etc..)
If you take sizeof("abc"); you are taking the size of a character array with size 4 (e.g. {'a', 'b', 'c', '\0'}), because a string literal is an array of char initialized to hold the string "abc" (including the nul-terminating character). Also note, that on virtually all systems, a string literal is created in read-only memory and cannot be modified, it is immutable.
If you want to allocate storage to hold a copy of the string "abc", you must allocate strlen("abc") + 1 characters (the +1 for the nul-terminating character '\0' -- which is simply ASCII 0, see ASCII Table & Description.
Whenever you allocate memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed. So if you allocate for char *st = malloc (len + 1); characters, you do not want to iterate with the pointer st (e.g. no st++). Instead, declare a second pointer, char *p = st; and you are free to iterate with p.
Also, in C, there is no need to cast the return of malloc, it is unnecessary. See: Do I cast the result of malloc?.
If you want to add to an allocation, you use realloc() which will create a new block of memory for you and copy your existing block to it. When using realloc(), you always reallocate using a temporary pointer (e.g. don't st = realloc (st, new_size);) because if when realloc() fails, it returns NULL and if you assign that to your pointer st, you have just lost the original pointer and created a memory leak. Instead, use a temporary pointer, e.g. void *tmp = realloc (st, new_size); then validate realloc() succeeds before assigning st = tmp;
Now, reading between the lines that is where you are going with your example, the following shows how that can be done, keeping track of the amount of memory allocated and the amount of memory used. Then when used == allocated, you reallocate more memory (and remembering to ensure you have +1 bytes available for the nul-terminating character.
A short example would be:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define THISMANY 23
int main (void) {
char *s = "abc", *st, *p; /* string literal and pointer st */
size_t len = strlen(s), /* length of s */
allocated = len + 1, /* number of bytes in new block allocated */
used = 0; /* number of bytes in new block used */
st = malloc (allocated); /* allocate storage for copy of s */
p = st; /* pointer to allocate, preserve st */
if (!st) { /* validate EVERY allocation */
perror ("malloc-st");
return 1;
}
for (int i = 0; s[i]; i++) { /* copy s to new block of memory */
*p++ = s[i]; /* (could use strcpy) */
used++; /* advance counter */
}
*p = 0; /* nul-terminate copy */
for (size_t i = 0; i < THISMANY; i++) { /* loop THISMANY times */
if (used + 1 == allocated) { /* check if realloc needed (remember '\0') */
/* always realloc using temporary pointer */
void *tmp = realloc (st, 2 * allocated); /* realloc 2X current */
if (!tmp) { /* validate EVERY reallocation */
perror ("realloc-st");
break; /* don't exit, original st stil valid */
}
st = tmp; /* assign reallocated block to st */
allocated *= 2; /* update allocated amount */
}
*p++ = 'a' + used++; /* assign new char, increment used */
}
*p = 0; /* nul-terminate */
printf ("result st : %s\n" /* output final string, length, allocated */
"length st : %zu bytes\n"
"final size : %zu bytes\n", st, strlen(st), allocated);
free (st); /* don't forget to free what you have allocated */
}
Example Use/Output
$ ./bin/sizeofs
result st : abcdefghijklmnopqrstuvwxyz
length st : 26 bytes
final size : 32 bytes
Look things over and let me know if this answered your questions, and if not, leave a comment and I'm happy to help further.
If you are still shaky on what a pointer is, and would like more information, here are a few links that provide basic discussions of pointers that may help. Difference between char pp and (char) p? and Pointer to pointer of structs indexing out of bounds(?)... (ignore the titles, the answers discuss pointer basics)
Can someone explain to me why my call to malloc with a string size of 6 returns a sizeof of 4 bytes? In fact, any integer argument I give malloc I get a sizeof of 4. Next, I am trying to copy two strings. Why is my ouput of the copied string (NULL)?
Following is my code:
int main()
{
char * str = "string";
char * copy = malloc(sizeof(str) + 1);
printf("bytes allocated for copy: %d\n", sizeof(copy));
while(*str != '\0'){
*copy = *str;
str++;
copy++;
}
copy = '\0';
printf("%s\n", copy);
}
sizeof(str) returns the size of a pointer of type char*. What you should do is to malloc the size of the string it self:
char * copy = malloc(strlen(str) + 1);
Also, these lines:
while(*str != '\0'){
*copy = *str;
str++;
copy++;
}
copy = '\0';
Can be rewritten easily in C like this:
while(*copy++ = *str++);
First you should understand that sizeof(xxx) where xxx is any left value expression (a variable) is always equivalent to do sizeof(type of xxx). Hence what is really doing your sizeof(str) is returning the size of a char *, that is the size of any other pointer. On a 32 bits architecture you'll get 4, on a 64 bits architecture it'll be 8, etc.
So, as others also explained you have to know the length of the string you want to allocate, and then add 1 to store the terminal \0, C implicitly use to put at the end of strings.
But to do what you want (copy a string and allocate necessary space) it will be more simple and more efficient to use strdup, that does exactly that : a malloc and a strcopy.
You should also not forget to free space you allocated yourself (using malloc, calloc, strdup or any other allocation function). In C it won't go away when allocated variable go out of scope. It will stay used until the end of the program. That's what you call a memory leak.
#include <string.h> /* for strdup, strlen */
#include <stdio.h> /* for printf */
int main()
{
char * str = "string";
char * copy = strdup(str);
printf("bytes at least allocated for copy: %d\n", strlen(copy)+1);
printf("%s\n", copy);
free(copy);
}
One last point : I changed message to bytes at least allocated because you don't really know the size allocated when calling malloc. It quite often allocates a slighly more space that what you asked for. One reason is that in many memory managers free blocks are linked together using some hidden data structure and any allocated block should be able to contain at least such structure, another is that allocated blocks are always aligned in such a way to be compatible with any type alignment.
Hope it will help you to understand C a little better.
You're getting the size of the str pointer (4 bytes), not what it's pointing to?
sizeof(str) returns the space necessary to store the pointer to the string, not the string itself. You can see the size of the string with strlen(str) for example.
Then you affect your copy pointer to an integer which has the value 0 (the character '\0'). It is the same as copy = NULL, which is what the printf() function shows you.
sizeof() returns the size of the actual type of the variable. So, when you define your type as char *, it returns the size of a pointer.
But if you made your variable an array, sizeof would return the size of the array itself, which would do what you want to do:
char *ptr = "moo to you";
char arr[] = "moo to you";
assert(sizeof(ptr) == 4); // assuming 32 bit
assert(sizeof(arr) == 11); // sizeof array includes terminating NUL
assert(strlen(arr) == 10); // strlen does not include terminating NUL
To tackle your second questions, by executing the statement copy++ you have changed the value of copy (that is, the address in memory that holds a char array) so that by the time you print it out, it is pointing at the end of the array rather than the beginning (the value returned by malloc()). You will need an extra variable to update the string and be able to access the beginning of the string:
Edit to repair malloc/sizeof issue - thanks CL.
char * str = "string";
/* char * copy = malloc(sizeof(str) + 1); Oops */
char * copy = malloc(strlen(str) + 1);
char * original_copy = copy;
printf("bytes allocated for copy: %d\n", sizeof(copy));
while(*str != '\0'){
*copy = *str;
str++;
copy++;
}
copy = '\0';
printf("%s\n", original_copy);
sizeof() returns you the size of the pointer and not the amount of allocated bytes. You don't need to count the allocated bytes, just check if the returned pointer is not NULL.
The line copy = '\0'; resets the pointer and makes it NULL.
You can use:
size_t malloc_usable_size (void *ptr);
instead of : sizeof
But it returns the real size of the allocated memory block! Not the size you passed to malloc!
When I do this
char *paths[10];
paths[0] = "123456";
printf(1,"%s\n",paths[0]);
printf(1,"%c\n",paths[0][2]);
Output:
123456
3
But when I you do this
char *paths[10];
paths[0][0]='1';
paths[0][1]='2';
paths[0][2]='3';
paths[0][3]='4';
paths[0][4]='5';
paths[0][5]='6';
printf(1,"%s\n",paths[0]);
printf(1,"%c\n",paths[0][2]);
Output:
(null)
3
Why it is null in this case?
How to create a string array using characters in C? I am a bit new to C and feeling some difficulties to program in C
You have a lot of options provided by various answers, I'm just adding a few points.
You can create a string array as follows:
I. You can create an array of read only strings as follows:
char *string_array0[] = {"Hello", "World", "!" };
This will create array of 3 read-only strings. You cannot modify the characters of the string in this case i.e. string_array0[0][0]='R'; is illegal.
II. You can declare array of pointers & use them as you need.
char *string_array1[2]; /* Array of pointers */
string_array1[0] = "Hey there"; /* This creates a read-only string */
/* string_array1[0][0] = 'R';*/ /* This is illegal, don't do this */
string_array1[1] = malloc(3); /* Allocate memory for 2 character string + 1 NULL char*/
if(NULL == string_array1[1])
{
/* Handle memory allocation failure*/
}
string_array1[1][0] = 'H';
string_array1[1][1] = 'i';
string_array1[1][2] = '\0'; /* This is important. You can use 0 or NULL as well*/
...
/* Use string_array1*/
...
free(string_array1[1]); /* Don't forget to free memory after usage */
III. You can declare a two dimensional character array.
char string_array2[2][4]; /* 2 strings of atmost 3 characters can be stored */
string_array2[0][0] = 'O';
string_array2[0][1] = 'l';
string_array2[0][2] = 'a';
string_array2[0][3] = '\0';
string_array2[1][0] = 'H';
string_array2[1][1] = 'i';
string_array2[1][2] = '\0'; /* NUL terminated, thus string of length of 2 */
IV. You can use pointer to pointer.
char ** string_array3;
int i;
string_array3 = malloc(2*sizeof(char*)); /* 2 strings */
if(NULL == string_array3)
{
/* Memory allocation failure handling*/
}
for( i = 0; i < 2; i++ )
{
string_array3[i] = malloc(3); /* String can hold at most 2 characters */
if(NULL == string_array3[i])
{
/* Memory allocation failure handling*/
}
}
strcpy(string_array3[0], "Hi");
string_array3[1][0]='I';
string_array3[1][1]='T';
string_array3[1][2]='\0';
/*Use string_array3*/
for( i = 0; i < 2; i++ )
{
free(string_array3[i]);
}
free(string_array3);
Points to remember:
If you are creating read-only string, you cannot change the character
in the string.
If you are filling the character array, make sure you have
memory to accommodate NUL character & make sure you terminate your
string data with NUL character.
If you are using pointers &
allocating memory, make sure you check if memory allocation is done
correctly & free the memory after use.
Use string functions from
string.h for string manipulation.
Hope this helps!
P.S.: printf(1,"%s\n",paths[0]); looks shady
char *paths[10];
paths[0][0]='1';
paths is an array of pointers. paths is not initialized to anything. So, it has garbage values. You need to use allocate memory using malloc. You just got unlucky that this program actually worked silently. Think of what address location would paths[0][0] would yield to assign 1 to it.
On the other hand, this worked because -
char *paths[10];
paths[0] = "123456";
"123456" is a string literal residing in the reading only location. So, it returns the starting address of that location which paths[0] is holding. To declare correctly -
const char* paths[10];
paths is an array of 10 pointers to char. However, the initial elements are pointers which can not be dereferenced. These are either wild (for an array in a function) or NULL for a static array. A wild pointer is an uninitialized one.
I would guess yours is static, since paths[0] is NULL. However, it could be a coincidence.
When you dereference a NULL or uninitialized pointer, you're reading or writing to memory you don't own. This causes undefined behavior, which can include crashing your program.
You're actually lucky it doesn't crash. This is probably because the compiler sees you're writing a constant to paths[0][2], and changes your printf to print the constant directly. You can not rely on this.
If you want to have a pointer you're allowed to write to, do:
paths[0] = malloc(string_length + 1);
string_length is the number of characters you can write. The 1 gives you room for a NUL. When you're done, you have to free it.
For your second example, if you know the size of each string you can write e.g.
char paths[10][6];
paths[0][0]='1';
...
paths[0][5]='6';
This way you have 10 strings of length 6 (and use only the first string so far).
You can define the string yourself, right after
#inlcude <stdio.h>
like this
typedef char string[];
and in main you can do this
string paths = "123456";
printf("%s\n", paths);
return 0;
so your code would look like this
#include <stdio.h>
typedef char string[];
int main() {
string paths = "123456";
printf("%s", paths);
}
gcc 4.4.4 c89
I understand pointers ok. However, I am stepping up to pointer arrays and pointers to pointers.
I have been messing around with this code snippet and have left comments of what I think I understand.
Many thanks for any advice if my comments are correct with the line of code?
void increment_ptr()
{
/* Static char array */
char src[] = "rabbit";
/* pointer to array of pointers to char's - create 6 pointers in this array */
char *dest[sizeof(src)];
size_t i = 0;
/* pointer to a char */
char* chr_ptr = NULL;
/* pointer to pointer that points to a char */
char** ptr_ptr = NULL;
/* chr_ptr pointer now points to the memory location where 'rabbit' is stored. */
chr_ptr = src;
/* ptr_ptr points to the first memory address of the pointer array of where dest is stored */
ptr_ptr = dest;
/* Deference chr_ptr and keep going until nul is reached 'rabbit\0' */
while(*chr_ptr != '\0')
/* deference ptr_ptr and assign the address of each letter to the momory location where
ptr_ptr is currently pointing to. */
*ptr_ptr++ = chr_ptr++;
/* reset the ptr_ptr to point to the first memory location 'rabbit' */
ptr_ptr = dest;
/* Keep going until NULL is found - However, my program never finds it, ends in UB */
while(ptr_ptr != NULL) {
/* Dereference what the pointer to pointer is pointing at the memory lcoation */
printf("[ %s ]\n", *ptr_ptr++);
}
}
Comments below each part (bits I haven't mentioned are correct):
/* Static char array */
char src[] = "rabbit";
This array is not static - it has auto storage duration.
/* pointer to array of pointers to char's - create 6 pointers in this array */
char *dest[sizeof(src)];
This is an array of pointers to char, not a pointer to an array. The length of the array is 7, because the sizeof(src) is 7 (it includes the nul string terminator).
/* chr_ptr pointer now points to the memory location where 'rabbit' is stored. */
chr_ptr = src;
More precisely, it points at the first character in src, which is the 'r' in "rabbit".
/* ptr_ptr points to the first memory address of the pointer array of where dest is stored */
ptr_ptr = dest;
It points at the first pointer in the dest array.
/* Keep going until NULL is found - However, my program never finds it, ends in UB */
while(ptr_ptr != NULL) {
Correct - because you never initialised dest. You could change the declaration of dest to this:
char *dest[sizeof(src)] = { 0 };
...and it will work.
I would suggest that you read Section 6 of the online C-FAQ: 6. Arrays and Pointers
The error is when you assign dest to ptr_ptr, which is actually an uninitialized array of pointers to chars, going through it withing the while loop will fail.
/* reset the ptr_ptr to point to the first memory location 'rabbit' */
ptr_ptr = dest;
/* Keep going until NULL is found - However, my program never finds it, ends in UB */
while(ptr_ptr != NULL) {
/* Dereference what the pointer to pointer is pointing at the memory lcoation */
printf("[ %s ]\n", *ptr_ptr++);
}