char [length] initialization and dealing with it - c

I have defined a char array:
char d[6];
Correct me if I'm wrong regarding following:
At this moment no memory is allocated for variable d. Now I'm going to initialize it:
d="aaaaa";
After this kind of initialization, there would be no need to free memory; it will be done automatically.
How do I know if the char[] was initialized? I am looking for a pattern like
if (filled(d)){..}
Also, how do I fill char[] with one kind of character?

At this moment no memory allocated for variable d.
Incorrect. This:
char d[6];
is an uninitialised array of 6 chars and memory, on stack, has been allocated for it. Stack variables do not need to be explicitly free()d, whether they are initialised or not. The memory used by a stack variable will be released when it goes out of scope. Only pointers obtained via malloc(), realloc() or calloc() should be passed to free().
To initialise:
char d[6] = "aaaaa"; /* 5 'a's and one null terminator. */
or:
char d[] = "aaaaa"; /* The size of the array is inferred. */
And, as already noted by mathematician1975, array assignment is illegal:
char d[] = "aaaaa"; /* OK, initialisation. */
d = "aaaaa"; /* !OK, assignment. */
strcpy(), strncpy(), memcpy(), snprintf(), etc can be used to copy into d after declaration, or assignment of char to individual elements of d.
How to know was char[] initialized? I need pattern if filled(d){..}
If the arrays are null terminated you can use strcmp()
if (0 == strcmp("aaaaaa", d))
{
/* Filled with 'a's. */
}
or use memcmp() if not null terminated:
if (0 == memcmp("aaaaaa", d, 6))
{
/* Filled with 'a's. */
}
How to fill char[] with one kind of characters?
Use memset():
memset(d, 'a', sizeof(d)); /* WARNING: no null terminator. */
or:
char d[] = { 'a', 'a', 'a', 'a', 'a', 'a' }; /* Again, no null. */

Your code will not compile (gcc 4.6.3) if you do
char d[6];
d = "aaaaa";
you will need to do
char d[6] = "aaaaa"
to initialise it this way.
This is a local variable created on the stack and so in terms of memory issues all you need worry about is not writing/reading beyond the array bounds.

First, whenever you declare char d[6] 6 bytes of memory is already allocated.
Second, no need to free your memory unless you do malloc
Third, if you want to initialize it with one kind of character then do this
char d[6] = "aaaaa";

int d[6];
6 bytes will be allocated onto the stack with this declaration. It will be freed automatically.

How to know was char[] initialized? I need pattern if filled(d){..}
Just do this while declaring the character array:
char d[6];
d[0] = 0;
Then you can check like this:
if(strlen(d) == 0)
//d is not initialized

Related

How do I make a function return a pointer to a new string in C?

I'm reading K&R and I'm almost through the chapter on pointers. I'm not entirely sure if I'm going about using them the right way. I decided to try implementing itoa(n) using pointers. Is there something glaringly wrong about the way I went about doing it? I don't particularly like that I needed to set aside a large array to work as a string buffer in order to do anything, but then again, I'm not sure if that's actually the correct way to go about it in C.
Are there any general guidelines you like to follow when deciding to use pointers in your code? Is there anything I can improve on in the code below? Is there a way I can work with strings without a static string buffer?
/*Source file: String Functions*/
#include <stdio.h>
static char stringBuffer[500];
static char *strPtr = stringBuffer;
/* Algorithm: n % 10^(n+1) / 10^(n) */
char *intToString(int n){
int p = 1;
int i = 0;
while(n/p != 0)
p*=10, i++;
for(;p != 1; p/=10)
*(strPtr++) = ((n % p)/(p/10)) + '0';
*strPtr++ = '\0';
return strPtr - i - 1;
}
int main(){
char *s[3] = {intToString(123), intToString(456), intToString(78910)};
printf("%s\n",s[2]);
int x = stringToInteger(s[2]);
printf("%d\n", x);
return 0;
}
Lastly, can someone clarify for me what the difference between an array and a pointer is? There's a section in K&R that has me very confused about it; "5.5 - Character Pointers and Functions." I'll quote it here:
"There is an important difference between the definitions:
char amessage[] = "now is the time"; /*an array*/
char *pmessage = "now is the time"; /*a pointer*/
amessage is an array, just big enough to hold the sequence of characters and '\0' that
initializes it. Individual characters within the array may be changed but amessage will
always refer to the same storage. On the other hand, pmessage is a pointer, initialized
to point to a string constant; the pointer may subsequently be modified to point
elsewhere, but the result is undefined if you try to modify the string contents."
What does that even mean?
For itoa the length of a resulting string can't be greater than the length of INT_MAX + minus sign - so you'd be safe with a buffer of that length. The length of number string is easy to determine by using log10(number) + 1, so you'd need buffer sized log10(INT_MAX) + 3, with space for minus and terminating \0.
Also, generally it's not a good practice to return pointers to 'black box' buffers from functions. Your best bet here would be to provide a buffer as a pointer argument in intToString, so then you can easily use any type of memory you like (dynamic, allocated on stack, etc.). Here's an example:
char *intToString(int n, char *buffer) {
// ...
char *bufferStart = buffer;
for(;p != 1; p/=10)
*(buffer++) = ((n % p)/(p/10)) + '0';
*buffer++ = '\0';
return bufferStart;
}
Then you can use it as follows:
char *buffer1 = malloc(30);
char buffer2[15];
intToString(10, buffer1); // providing pointer to heap allocated memory as a buffer
intToString(20, &buffer2[0]); // providing pointer to statically allocated memory
what the difference between an array and a pointer is?
The answer is in your quote - a pointer can be modified to be pointing to another memory address. Compare:
int a[] = {1, 2, 3};
int b[] = {4, 5, 6};
int *ptrA = &a[0]; // the ptrA now contains pointer to a's first element
ptrA = &b[0]; // now it's b's first element
a = b; // it won't compile
Also, arrays are generally statically allocated, while pointers are suitable for any allocation mechanism.
Regarding your code:
You are using a single static buffer for every call to intToString: this is bad because the string produced by the first call to it will be overwritten by the next.
Generally, functions that handle strings in C should either return a new buffer from malloc, or they should write into a buffer provided by the caller. Allocating a new buffer is less prone to problems due to running out of buffer space.
You are also using a static pointer for the location to write into the buffer, and it never rewinds, so that's definitely a problem: enough calls to this function, and you will run off the end of the buffer and crash.
You already have an initial loop that calculates the number of digits in the function. So you should then just make a new buffer that big using malloc, making sure to leave space for the \0, write in to that, and return it.
Also, since i is not just a loop index, change it to something more obvious like length:
That is to say: get rid of the global variables, and instead after computing length:
char *s, *result;
// compute length
s = result = malloc(length+1);
if (!s) return NULL; // out of memory
for(;p != 1; p/=10)
*(s++) = ((n % p)/(p/10)) + '0';
*s++ = '\0';
return result;
The caller is responsible for releasing the buffer when they're done with it.
Two other things I'd really recommend while learning about pointers:
Compile with all warnings turned on (-Wall etc) and if you get an error try to understand what caused it; they will have things to teach you about how you're using the language
Run your program under Valgrind or some similar checker, which will make pointer bugs more obvious, rather than causing silent corruption
Regarding your last question:
char amessage[] = "now is the time"; - is an array. Arrays cannot be reassigned to point to something else (unlike pointers), it points to a fixed address in memory. If the array was allocated in a block, it will be cleaned up at the end of the block (meaning you cannot return such an array from a function). You can however fiddle with the data inside the array as much as you like so long as you don't exceed the size of the array.
E.g. this is legal amessage[0] = 'N';
char *pmessage = "now is the time"; - is a pointer. A pointer points to a block in memory, nothing more. "now is the time" is a string literal, meaning it is stored inside the executable in a read only location. You cannot under any circumstances modify the data it is pointing to. You can however reassign the pointer to point to something else.
This is NOT legal -*pmessage = 'N'; - will segfault most likely (note that you can use the array syntax with pointers, *pmessage is equivalent to pmessage[0]).
If you compile it with gcc using the -S flag you can actually see "now is the time" stored in the read only part of the assembly executable.
One other thing to point out is that arrays decay to pointers when passed as arguments to a function. The following two declarations are equivalent:
void foo(char arr[]);
and
void foo(char* arr);
About how to use pointers and the difference between array and pointer, I recommend you read the "expert c programming" (http://www.amazon.com/Expert-Programming-Peter-van-Linden/dp/0131774298/ref=sr_1_1?ie=UTF8&qid=1371439251&sr=8-1&keywords=expert+c+programming).
Better way to return strings from functions is to allocate dynamic memory (using malloc) and fill it with the required string...return this pointer to the calling function and then free it.
Sample code :
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#define MAX_NAME_SIZE 20
char * func1()
{
char * c1= NULL;
c1 = (char*)malloc(sizeof(MAX_NAME_SIZE));
strcpy(c1,"John");
return c1;
}
main()
{
char * c2 = NULL;
c2 = func1();
printf("%s \n",c2);
free(c2);
}
And this works without the static strings.

Cannot assign char to char pointer

Here is my code:
printf("%s\n", "test1");
char c = '2';
char * lines[2];
char * tmp1 = lines[0];
*tmp1 = c;
printf("%s\n", "test2");
I don't see the second printf in console.
Question: Can anybody explain me what's wrong with my code?
NOTE: I'm trying to learn C :)
This line:
char * lines[2];
declares an array of two char pointers. However, you don't actually initialize the pointers to anything. So later when you do *tmp1 = (char)c; then you assign the character c to somewhere in memory, possibly even address zero (i.e. NULL) which is a bad thing.
The solution is to either create the array as an array of arrays, like
char lines[2][30];
This declares lines to have two arrays of 30 characters each, and since strings needs a special terminator character you can have string of up to 29 characters in them.
The second solution is to dynamically allocate memory for the strings:
char *lines[2];
lines[0] = malloc(30);
lines[1] = malloc(30);
Essentially this does the same as the above array-of-arrays declaration, but allocates the memory on the heap.
Of course, maybe you just wanted a single string of a single character (plus the terminator), then you were almost right, just remove the asterisk:
char line[2]; /* Array of two characters, or a string of length one */
The array lines in uninitialized. Thus lines[0] is an uninitalized pointer. Dereferencing it in *tmp1 is sheer undefined behaviour.
Here's an alternative, that may or may not correspond to what you want:
char lines[2];
char * tmp1 = lines; // or "&lines[0]"
*tmp = c;
Or, more easily:
char lines[2] = { c, 0 };
lines is uninitialized, and tmp1 initialization is wrong.
It should be:
char lines[2];
char * tmp1 = lines;
Alternatively, you can say:
char * tmp1 = &lines[0];
Or else for an array of strings:
char lines[2][30];
char * tmp1 = lines[0];
The line
char * lines[2];
creates an array of two char pointers. But that doesn't allocate memory, it's just a "handle" or "name" for the pointer in memory. The pointer doesn't point to something useful.
You will either have to allocate memory using malloc():
char * lines = malloc(2);
or tell the compiler to allocate memory for you:
char lines[2];
Note: Don't forget to terminate the string with a 0 byte before you use it.
char *lines[2]; : A two element array of char pointers.
char *tmp; : A pointer to a character.
char *tmp = lines[0] : The value inside the array element 0 of the lines array is transferred into tmp. Because it is an automatic array, therefore it will have garbage as the value for lines[0].
*temp : Dereference the garbage value. Undefined Behaviour.
char * tmp1 = lines[0];
here you declare a char pointer and initialize its pointer value to line[0],the fist element stored in line array which is also uninitialized.
now the tmp is pointing to somewhere unknown and not actually accessible. When you
*tmp1 = (char)c;
you are operating on a invalid memory address which causes a Segmentation fault.

error in using realloc in C/C++

char *t = malloc(2);
t = "as";
t = realloc(t,sizeof(char)*6);
I am getting error "invalid pointer: 0x080488d4 *"..
I am getting strange errors in using memory allocation functions. Is there any good tuts/guides which could explain me memory allocation functions.
I am using linux..
Please help..
This is your problem:
char *t = malloc(2);
t = "as";
You probably thought this would copy the two-character string "as" into the buffer you just allocated. What it actually does is throw away (leak) the buffer, and change the pointer to instead point to the string constant "as", which is stored in read-only memory next to the machine code, not on the malloc heap. Because it's not on the heap, realloc looks at the pointer and says "no can do, that's not one of mine". (The computer is being nice to you by giving you this error; when you give realloc a pointer that wasn't returned by malloc or realloc, the computer is allowed to make demons fly out of your nose if it wants.)
This is how to do what you meant to do:
char *t = malloc(3);
strcpy(t, "as");
Note that you need space for three characters, not two, because of the implicit NUL terminator.
By the way, you never need to multiply anything by sizeof(char); it is 1 by definition.
That is not how you assign strings in C.
The correct syntax is:
char* t = malloc(3); // Reserve enough space for the null-terminator \0
strncpy(t, "as", 3);
// Copy up to 3 bytes from static string "as" to char* t.
// By specifying a maximum of 3 bytes, prevent buffer-overruns
Allocating 2-bytes is NOT enough for "as".
C-strings have a 1-byte null-terminator, so you need at least 3 bytes to hold "as\0".
(\0 represents the null-terminator)
The code you wrote: t = "as"; makes the pointer t "abandon" the formerly allocated memory, and instead point to the static string "as". The memory allocated with malloc is "leaked" and cannot be recovered (until the program terminates and the OS reclaims it).
After this, you can call realloc as you originally did.
However, you should not do t = realloc(t,6);. If realloc fails for any reason, you've lost your memory.
The preferred method is:
new_t = realloc(t, 6);
if (new_t != NULL) // realloc succeeded
{ t = new_t;
}
else
{ // Error in reallocating, but at least t still points to good memory!
}
Your code reassigns t, making it point elsewhere
char *t = malloc(2); //t=0xf00ba12
t = "as"; //t=0xbeefbeef
t = realloc(t,sizeof(char)*6); //confused because t is 0xbeefbeef, not 0xf00b412.
Instead use strcpy
char *t = malloc(3); //don't forget about the '\0'
strcpy(t, "as");
t = realloc(t, 6); //now the string has room to breathe
First off, don't do that:
char *t = malloc(2);
Do this instead:
char *t = malloc(2 * sizeof(char));
/* or this: */
char *t = calloc(2, sizeof(char));
It may not seem worth the effort, but otherwise you may run into problems later when you deal with types larger than 1 byte.
In this line:
t = "as";
You're assigning the address of the string literal "as", so your pointer no longer points to the memory you allocated. You need to copy the contents of the literal to your allocated memory:
char *t = calloc(3, sizeof(char));
/* "ar" is 3 char's: 'a', 'r' and the terminating 0 byte. */
strncpy(t, "ar", 3);
/* then later: */
t = realloc(t,sizeof(char)*6);
You can also just use strdup, which is safer:
#include <string.h>
char *t = strdup("ar");
t = realloc(t,sizeof(char)*6);
And don't forget to free the memory
free(t);
char *t = malloc(2);
this means you have created a pointer to a memory location that can hold 2 bytes
+-+-+
t -> | | |
+-+-+
when you do
t = "as";
now you made t point to somewhere else than what it originally was pointing to. now it no longer points to the heap
t = realloc(t,sizeof(char)*6);
now you are taking the pointer pointing to read only memory and try to realloc it.
when you use malloc you allocate space on the heap. t in this case is a pointer to that location, an address of where the block is.
in order to put something in that spot you need to copy the data there by dereferencing t, this is done by writing * in front of t:
*t = 'a'; // now 'a' is where t points
*(t+1)='s'; // now 's' is behind a, t still pointing to 'a'
however in C, a string is always terminated with a 0 (ASCII value) written as '\0' so in order to make it a string you need to append a \0
+-+-+--+
t -> |a|s|\0|
+-+-+--+
in order to do this you need to malloc 3 bytes instead, than you can add the \0 by writing *(t+2)='\0';
now t can be treated as pointing to a string and used in functions that takes strings as arguments e.g. strlen( t ) returns 2

Create a string array with Characters in C

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);
}

Initializing arrays of type char

I want to initialize arbitrary large strings. It is null terminated string of characters, but I cannot print its content.
Can anybody tell me why?
char* b;
char c;
b = &c;
*b = 'm';
*(b+1) = 'o';
*(b+2) = 'j';
*(b+3) = 'a';
*(b+4) = '\0';
printf("%s\n", *b);
Your solution invokes undefined behaviour, because *(b+1) etc. are outside the bounds of the stack variable c. So when you write to them, you're writing all over memory that you don't own, which can cause all sorts of corruption. Also, you need to printf("%s\n", b) (printf expects a pointer for %s).
The solution depends on what you want to do. You can initialize a pointer to a string literal:
const char *str1 = "moja";
You can initialize a character array:
char str2[] = "moja";
This can also be written as:
char str2[] = { 'm', 'o', 'j', 'a', '\0' };
Or you can manually assign the values of your string:
char *str3 = malloc(5);
str3[0] = 'm';
str3[1] = 'o';
str3[2] = 'j';
str3[3] = 'a';
str3[4] = '\0';
...
free(str3);
This might result in a segmentation fault! *(b+1), *(b+2) etc refer to unallocated areas. First allocate memory and then write into it!
b doesn't have enough space to hold all those characters. Allocate enough space using malloc or declare b as a char array.
Your code is not safe at all! You allocate only 1 char on the stack with char c; but write 5 chars into it! this will give you a stack-overflow which can be very dangerous.
Another thing: you mustn't dereference the string when printing it: printf("%s\n", b);
Why not simply write const char *b = "mojo";?
You need to assign memory space for it, either with malloc or using a static array. Here, in your code, you're using the address of just one character to store at the addresses of that characters, and others following it. This is not defined.
Note, step by step, what you're doing. First, you assign the pointer to point to a single char space in memory. Then, by using *b = 'm' you set that memory to the character 'm'. But then, you access to the next memory position (that is undefined, because no memory is reserved for that position) to store another value. This won't work.
How to do it?
You have two options. For example:
char *b;
char c[5];
b = &c[0];
*b = 'm';
... //rest of your code
This will work because you have space for 5 chars in c. The other option is to directly assign memory for b using malloc:
char * b = (char*) malloc(5);
*b = 'm';
... // rest of your code
Finally, maybe not what you want, but you can either initialize a char array or pointer using a string literal:
char c[] = "hello";
const char* b = "abcdef";
The printf does not print because it expect a char*, so you should pass b, not *b.
To initialize a pointer to a string constant you can do something like:
char *s1 = "A string"
or
char s2[] = "Another string"
or allocate a buffer with char *b = malloc(5) and then write to this buffer (as you did, or with the string functions)
what you did was taking the address of a single char memory location and then write past to it, possibly overwriting other variables or instructions and thus possibly leading to data corruption or crash.
If you write the following instead of your printf, it will print the first character.
printf("%c\n", *b);
In order for you to have arbitrarily large strings, you will need to use a library such as bstring or write one of your own.
This is because, in C one needs to get memory, use it and free it accordingly. b in your case only points to a character unless you allocate memory to it using malloc. And for malloc you have to specify a fixed size.
For arbitrarily large string, you need to encapsulate the actual pointer to character in a data structure of your own, and then manage its size according to the length of the string that is to be set as its value.
printf("%s\n", *b);
why *?
printf("%s\n", b);
is what you want

Resources