I am actually supposed to dynamically store a string. I have tried the below,
It is printing everything but it terminating as soon as a space is included in my input. can someone explain is why?
Also what is the right way to do it :
int i;
char *a;
a=(char *)malloc(sizeof(char));
scanf("%s",a);
for(i=0;*(arr+i)!='\0';i++)
printf("%c",*(arr+i));
It is printing everything but it terminating ...
Consider your memory allocation statements:
char *a;
a=(char *)malloc(sizeof(char));
By allocating only sizeof(char) bytes to the buffer a, then attempting to write anything more than the null terminator to it, you are invoking undefined behavior. (Note: sizeof(char) in C is by definition equal to 1, always)
C strings are defined as a null terminated character array. You have allocated only one byte. The only legal C string possible is one containing only the null termination byte. But your code attempts to write much more, and in so doing encroaches on memory locations not owned by your process. So in general, when creating strings, follow two simple rules:
Determine max length of string you need
allocate memory to max length + 1 bytes to accommodate termination byte.
Example if max string is x characters long, create the memory for x + 1 characters:
char inputStr[] = {"This string is x char long"};
char string = malloc(strlen(inputStr) +1); //+1 for null byte
strcpy(string, inputStr);
Note, in C it is not recommended to cast the return of malloc() and family.
You've two problems with your code. Firstly, you only allocate enough space for 1 character and since strings have to be NUL terminated, the longest string you could have is 0 characters long. Since you don't know how long the text you're going to read in, you could start with an arbitrary size (say 1024).
a=malloc(1024);
Secondly, scanf will only read up to the next space when you use "%s". It also isn't constrained by the available space in a. A better way to to read in an entire line of text, is to use fgets like this
fgets(a,1024,stdin);
This will read up to 1023 characters or up to and including the next newline character. It will NUL terminate the string for you as well.
You can then print it as a string.
printf("%s",a);
char *a;
/* Initial memory allocation */
a = (char *) malloc(1024); // your buffer size is 1024
// do something with a
free(a);
Copy bellow string in your variable then print the string with "%s" as string and theres no need use of "%c" :
strcpy(a, "this is a string");
printf("String = %s", a);
Dont forget using of free(), if you dont use of this then you will get memory leak problem.
Related
Following is the piece of code
char str[20];
char *name[5];
for(i=0;i<5;i++){
printf("Enter a string");
gets(str);
name[i]=(char *)malloc(strlen(str));
strcpy(name[i],str);
}
When in line 5 address of each string(denoted by str variable) is stored in name[i] array, then why this code is copying each address into name[i] using strcpy()?
is this code correct?
Sorry, No. Please follow the below mentioned points.
Point 1
Please do not cast the return value of malloc() and family in C.
Point 2
malloc() is to allocate memory to the pointer. strcpy() is to fill the allocated memory. If you compare the code,
name[i]=malloc(<size>));
allocates memory of size bytes to name[i] pointer. but, the contains of the memory location is uninitialized or garbage.
strcpy(name[i],str);
it copies the containts of str to name[i]. After this, name[i] contains the same string as str.
Note:
That said, to strcpy() a string str, you need to malloc() for strlen(str) + 1 bytes, to have space for terminating null. Otherwise, you'll end up overrunning the allocated memory area which in turn invokes undefined behaviour.
Also, you should (IMHO, MUST) consider using fgets() over gets().
The strcpy() call copies the characters, not the pointer.
Also, you are under-allocating since you fail to include space for the terminating '\0' character. Thus, your code has undefined behavior.
So no, it's not correct (but the problem is not that it uses strcpy(), that's fine).
And perhaps it's not surprising that I too think that you should not cast the return value of malloc() in C.
Finally, you should never use gets(), it's very dangerous. Use fgets() instead, with a proper buffer size argument of course.
When you use malloc, you create a space in memory that equals the size of the string, but is an empty space, you have only an address.
You have to copy the value on the string to the name[i] array.
An analogy is, you have a pot with water, you can create another pot, but you only will have water on it, if you transfer from one to another.
the creation of the pot is the malloc function and the transfer of the contents is the strcpy.
char str[6]; //create a empty space for 6 characters
char *name[1]; //create a pointer for a location where
//the array will be stored, does not
//allocate any space
str = "abcdef" //assign letters to character array
name[1]=(char *)malloc(strlen(str+1)); //name[1] = _ _ _ _ _ _ _
//allocate space char array with
//size equal to str array plus 1
strcpy(name[1],str); //name[1] = a b c d e f /0
//copy the letters from one char
//array to the other
character array has 6 characters plus a null character to indicate end of array
Line 5 merely allocates space. The memory allocated by malloc() has unspecified values.
TL;DR;
malloc assigns memory for the process to use.
strcpy copies the required content into the malloced address space.
char *str;
printf("Enter string:\n");
scanf("%s",str);
OUTPUT:
runtime-check failure#3
str is being used without being initialized
Allocate an array and read into that:
char str[100];
if (scanf("%99s", str) != 1)
...error...
Or, if you need a pointer, then:
char data[100];
char *str = data;
if (scanf("%99s", str) != 1)
...error...
Note the use of a length to prevent buffer overflow. Note that the length specified to scanf() et al is one less than the total length (an oddity based on ancient precedent; most code includes the null byte in the specified length — see fgets(), for example).
Remember that %s will skip past leading white space and then stop on the first white space after some non-white space character. In particular, it will leave the newline in the input stream, ready for the next input operation to read. If you want the whole line of input, then you should probably use fgets() and sscanf() rather than raw scanf() — in fact, very often you should use fgets() and sscanf() rather than scanf() or fscanf(), if only because it make sensible error reporting a lot easier.
Its an undefined behavior if you dont initialize it.You have an uninitialized pointer which is reading data into memory location which may eventually cause trouble for you. You've declared str as a pointer, but you haven't given it a valid location to point to; it initially contains some random value that may or may not be a writable memory address.Try to allocate memory to the char *str;
char *str = malloc(sizeof(char)*100);
char *str declares str as a pointer to char type. scanf("%s",str) will read only E from the entered string.
You might NOT want to use exactly scanf("%s") (or get in the habit of using it) as it is vulnerable to buffer overflow (i.e. might accept more characters than your buffer can hold). For a discussion on this see Disadvantages of scanf
You have to allocate memory before assigning some value to a pointer. Always remember that pointer points to a memory location and you have to tell him what memory location you want to assign for him. So, for doing that you have to do :
str = (char*)malloc(sizeof(char));
This will assign you 1byte of memory block. So, you can assign only one character in this memory block. For a string you have to assign as many blocks depending on the number of characters in the string.Say, "Stack" requires 5 character and 1 extra block for '\0'. So, you have to assign at least 6 memory block to him.
str = (char*)malloc(6*sizeof(char));
I hope this will help you to grow more concepts in C.
is it possible to copy buffer to a string? strncpy can copy string into an allocated string array, i'm wondering if this is possible to do the opposite
char *buffer[50];
fgets(buffer, 50, stdin);
//how can i assign string in buffer to a single string (char)?
First, a C string is not just a char, but an array of char with the last element (or at least the last one that's counted as part of the string) set to the null character (numerically 0, also '\0' as a character constant).
Next, in the code you posted you probably meant char buffer[50] rather than char *buffer[50]... the version you have is an array of 50 char *s, but you need an array of 50 chars. After that's corrected, then...
Since fgets() always fills in a null char at the end of the string it read, buffer would already be a valid C string after you call fgets(). If you'd like to copy it to another string so you can reuse the buffer to read more input, you can use the usual string handling functions from <string.h>, such as strcpy(). Just make sure the string you copy it into is large enough to hold all the used characters plus a terminating null character.
This code copies the string into a newly malloc()ed string (error checking omitted):
char buffer[50];
char *str;
fgets(buffer,50,stdin);
str = malloc(strlen(buffer) + 1);
strcpy(str,buffer);
This code does the same, but copies to a char array on the stack (not malloc()ed):
char buffer[50];
char str[50];
fgets(buffer,50,stdin);
strcpy(str,buffer);
strlen() will tell you how many characters are used in the string, but doesn't count the terminating null (so you need to have one more character allocated than what strlen() returns). strcpy() will copy the characters and the null at the end from one string/buffer to another. It stops after the null, and doesn't know how much space you've allocated -- so you need to make sure it will find a null character before running out of space in the destination, or reaching the end of the source buffer. If in doubt, place a null at the end of the buffer yourself to make sure.
It should be char buffer[50]; and yes, you can then use strncpy (which does not care if it got a static or a heap allocated zone).
But I would recommend using getline in your case.
First of all, you must have:
char buffer[50];
because otherwise you have an array of 50 char *s which is not what you want. That is, you read 50 chars from input and create addresses from them (which means "boom"!)
Second, yes, you can use strncpy to copy. Note that a string is basically an array of chars, terminated by '\0' (NUL). So in this case, buffer is indeed a string. You would want to copy the string only if you want to keep the original and modify the second (or keep a copy of original and then modify buffer). Otherwise, you can safely use the same buffer as the desired string.
Third, I don't know how exactly your input looks like, but what you want to do, you can most likely do it better with *scanf functions.
char *a=NULL;
char *s=NULL;
a=(char *)calloc(1,(sizeof(char)));
s=(char *)calloc(1,(sizeof(char)));
a="DATA";
memcpy(s,a,(strlen(a)));
printf("%s",s);
Can you plz tell me why its printing DATA½½½½½½½½■ε■????How to print only DATA?? Thanks
Strings in C are terminated by a zero character value (nul).
strlen returns the number of characters before the zero.
So you are not copying the zero.
printf keeps going, printing whatever is in the memory after s until it hits a zero.
You also are only creating a buffer of size 1, so you are writing data over whatever is after s, and you leak the memory calloc'd to a before you set a to be a literal.
Allocate the memory for s after finding the length of the string, allocating one more byte to include the nul terminator, then copy a into s. You don't need to allocate anything for a as the C runtime looks after storing the literal "DATA".
strlen does only count the chars without the terminator '\0'.
Without this terminator printf does not know the end od the string.
Solution:
memcpy(s,a,(strlen(a)+1));
You are first allocating memory, then throwing that memory away by re-assigning the pointer using a string literal. Your arguments to calloc() also look very wrong.
Also, memcpy() is not a string copying function, it doesn't include the terminator. You should use strcpy().
The best way to print only DATA would seem to be
puts("DATA");
You need to be more clear on what you want to do, to get help with the pointers/allocations/copying.
Your
a="DATA";
trashes the pointer to the allocated memory. It does not copy "DATA" into the memory. Which however would be not enough to store it, since
a=(char *)calloc(1,(sizeof(char)));
allocates a single char. While
memcpy(s,a,(strlen(a)));
copies what is pointed now by a (string literal "DATA") to the memory which is pointed by s. But again, s points to a single char allocated, and copying more than 1 char will overwrite something and results in a bug.
strlen(a) gives you 4 (the length of "DATA") and memcpy copies exactly 4 char. But to know where a string ends, C uses the convention to put a final "null" char ('\0') to its end. So indeed "DATA" is, in memory, 'D' 'A' 'T' 'A' '\0'.
All string related function expect the null byte, and they don't stop printing until they find it.
To copy strings, use instead strcpy (or strncpy), it copies the string with its final null byte too. (strcpy is less "secure" since you can overflow the destination buffer).
But the biggest problem I can see here is that you reserve a single char only for a (and you trash it then) and s, so DATA\0 won't fit anywhere.
You are reserving space for 1 character so you are actually using the memory of some other variable when you are writing "DATA" (which is 4 characters + the trailing \0 to mark the end of the string).
a=(char *)calloc(1,(sizeof(char)));
For this example you would need 5 characters or more:
a=(char *)calloc(5, (sizeof(char)));
You need to store a terminating \0 after that DATA string so printf() will know to stop printing.
You could replace memcpy with strcat:
strcat(s, a);
should do it.
Note, however, that there's a bug earlier on:
calloc(1,sizeof(char))
will only allocate a single byte! That's certainly not enough! Depending on the implementation, your program may or may not crash.
I have never really done much C but am starting to play around with it. I am writing little snippets like the one below to try to understand the usage and behaviour of key constructs/functions in C. The one below I wrote trying to understand the difference between char* string and char string[] and how then lengths of strings work. Furthermore I wanted to see if sprintf could be used to concatenate two strings and set it into a third string.
What I discovered was that the third string I was using to store the concatenation of the other two had to be set with char string[] syntax or the binary would die with SIGSEGV (Address boundary error). Setting it using the array syntax required a size so I initially started by setting it to the combined size of the other two strings. This seemed to let me perform the concatenation well enough.
Out of curiosity, though, I tried expanding the "concatenated" string to be longer than the size I had allocated. Much to my surprise, it still worked and the string size increased and could be printf'd fine.
My question is: Why does this happen, is it invalid or have risks/drawbacks? Furthermore, why is char str3[length3] valid but char str3[7] causes "SIGABRT (Abort)" when sprintf line tries to execute?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main() {
char* str1 = "Sup";
char* str2 = "Dood";
int length1 = strlen(str1);
int length2 = strlen(str2);
int length3 = length1 + length2;
char str3[length3];
//char str3[7];
printf("%s (length %d)\n", str1, length1); // Sup (length 3)
printf("%s (length %d)\n", str2, length2); // Dood (length 4)
printf("total length: %d\n", length3); // total length: 7
printf("str3 length: %d\n", (int)strlen(str3)); // str3 length: 6
sprintf(str3, "%s<-------------------->%s", str1, str2);
printf("%s\n", str3); // Sup<-------------------->Dood
printf("str3 length after sprintf: %d\n", // str3 length after sprintf: 29
(int)strlen(str3));
}
This line is wrong:
char str3[length3];
You're not taking the terminating zero into account. It should be:
char str3[length3+1];
You're also trying to get the length of str3, while it hasn't been set yet.
In addition, this line:
sprintf(str3, "%s<-------------------->%s", str1, str2);
will overflow the buffer you allocated for str3. Make sure you allocate enough space to hold the complete string, including the terminating zero.
void main() {
char* str1 = "Sup"; // a pointer to the statically allocated sequence of characters {'S', 'u', 'p', '\0' }
char* str2 = "Dood"; // a pointer to the statically allocated sequence of characters {'D', 'o', 'o', 'd', '\0' }
int length1 = strlen(str1); // the length of str1 without the terminating \0 == 3
int length2 = strlen(str2); // the length of str2 without the terminating \0 == 4
int length3 = length1 + length2;
char str3[length3]; // declare an array of7 characters, uninitialized
So far so good. Now:
printf("str3 length: %d\n", (int)strlen(str3)); // What is the length of str3? str3 is uninitialized!
C is a primitive language. It doesn't have strings. What it does have is arrays and pointers. A string is a convention, not a datatype. By convention, people agree that "an array of chars is a string, and the string ends at the first null character". All the C string functions follow this convention, but it is a convention. It is simply assumed that you follow it, or the string functions will break.
So str3 is not a 7-character string. It is an array of 7 characters. If you pass it to a function which expects a string, then that function will look for a '\0' to find the end of the string. str3 was never initialized, so it contains random garbage. In your case, apparently, there was a '\0' after the 6th character so strlen returns 6, but that's not guaranteed. If it hadn't been there, then it would have read past the end of the array.
sprintf(str3, "%s<-------------------->%s", str1, str2);
And here it goes wrong again. You are trying to copy the string "Sup<-------------------->Dood\0" into an array of 7 characters. That won't fit. Of course the C function doesn't know this, it just copies past the end of the array. Undefined behavior, and will probably crash.
printf("%s\n", str3); // Sup<-------------------->Dood
And here you try to print the string stored at str3. printf is a string function. It doesn't care (or know) about the size of your array. It is given a string, and, like all other string functions, determines the length of the string by looking for a '\0'.
Instead of trying to learn C by trial and error, I suggest that you go to your local bookshop and buy an "introduction to C programming" book. You'll end up knowing the language a lot better that way.
There is nothing more dangerous than a programmer who half understands C!
What you have to understand is that C doesn't actually have strings, it has character arrays. Moreover, the character arrays don't have associated length information -- instead, string length is determined by iterating over the characters until a null byte is encountered. This implies, that every char array should be at least strlen + 1 characters in length.
C doesn't perform array bounds checking. This means that the functions you call blindly trust you to have allocated enough space for your strings. When that isn't the case, you may end up writing beyond the bounds of the memory you allocated for your string. For a stack allocated char array, you'll overwrite the values of local variables. For heap-allocated char arrays, you may write beyond the memory area of your application. In either case, the best case is you'll error out immediately, and the worst case is that things appear to be working, but actually aren't.
As for the assignment, you can't write something like this:
char *str;
sprintf(str, ...);
and expect it to work -- str is an uninitialized pointer, so the value is "not defined", which in practice means "garbage". Pointers are memory addresses, so an attempt to write to an uninitialized pointer is an attempt to write to a random memory location. Not a good idea. Instead, what you want to do is something like:
char *str = malloc(sizeof(char) * (string length + 1));
which allocates n+1 characters worth of storage and stores the pointer to that storage in str. Of course, to be safe, you should check whether or not malloc returns null. And when you're done, you need to call free(str).
The reason your code works with the array syntax is because the array, being a local variable, is automatically allocated, so there's actually a free slice of memory there. That's (usually) not the case with an uninitialized pointer.
As for the question of how the size of a string can change, once you understand the bit about null bytes, it becomes obvious: all you need to do to change the size of a string is futz with the null byte. For example:
char str[] = "Foo bar";
str[1] = (char)0; // I'd use the character literal, but this editor won't let me
At this point, the length of the string as reported by strlen will be exactly 1. Or:
char str[] = "Foo bar";
str[7] = '!';
after which strlen will probably crash, because it will keep trying to read more bytes from beyond the array boundary. It might encounter a null byte and then stop (and of course, return the wrong string length), or it might crash.
I've written all of one C program, so expect this answer to be inaccurate and incomplete in a number of ways, which will undoubtedly be pointed out in the comments. ;-)
Your str3 is too short - you need to add extra byte for null-terminator and the length of "<-------------------->" string literal.
Out of curiosity, though, I tried
expanding the "concatenated" string to
be longer than the size I had
allocated. Much to my surprise, it
still worked and the string size
increased and could be printf'd fine.
The behaviour is undefined so it may or may not segfault.
strlen returns the length of the string without the trailing NULL byte (\0, 0x00) but when you create a variable to hold the combined strings you need to add that 1 character.
char str3[length3 + 1];
…and you should be all set.
C strings are '\0' terminated and require an extra byte for that, so at least you should do
char str3[length3 + 1]
will do the job.
In sprintf() ypu are writing beyond the space allocated for str3. This may cause any type of undefined behavior (If you are lucky then it will crash). In strlen(), it is just searching for a NULL character from the memory location you specified and it is finding one in 29th location. It can as well be 129 also i.e. it will behave very erratically.
A few important points:
Just because it works doesn't mean it's safe. Going past the end of a buffer is always unsafe, and even if it works on your computer, it may fail under a different OS, different compiler, or even a second run.
I suggest you think of a char array as a container and a string as an object that is stored inside the container. In this case, the container must be 1 character longer than the object it holds, since a "null character" is required to indicate the end of the object. The container is a fixed size, and the object can change size (by moving the null character).
The first null character in the array indicates the end of the string. The remainder of the array is unused.
You can store different things in a char array (such as a sequence of numbers). It just depends on how you use it. But string function such as printf() or strcat() assume that there is a null-terminated string to be found there.