I must do this:
Write the function void AddName(char *Names[], int *size) that takes an array of strings Names and a pointer of integer size.
Checks if there is still enough space to store a new name.
If there is, asks the user to input his name and store it in a huge array of char (100 char).
Calculate the length of his name.
Allocate a dynamic memory to store his name and store its location in one of Names
indexes.
Increment the size by one.
I have wrote this code but malloc always allocate the same address so the whole array Names become similar
int const MAX = 3;
void AddName(char *Names[],int *size)
{
int tempsize = *size;
char *s;
if (tempsize > MAX)
printf("\n ERROR: Array is full. Cannot add.");
else
{
int i,len=0;
char name[100];
printf("Enter the name: ");
scanf("%s",name);
for(i=0; name[i]!='\0'; i++)
len++;
s = (char *)malloc((len+1)*sizeof(char));
s = &name;
Names[*size]=s;
*size=*size+1;
printf("\n Done.\n");
}
}
After you allocate your memory, you store the address into the variable s.
Then you overwrite that value with the address of your name variable.
As a result, you will never know the allocated address, because you discarded it with the overwriting.
s = &name;
This is wrong. You are obliterating the address that malloc just returned to you. What you want is to copy the contents of name to the memory position s. For that you need strncpy. Replace s = &name with:
strncpy(s, name, len);
Or, since you know that strlen(name) == len, and that you allocated enough memory, you can just use strcpy():
strcpy(s, name);
Related
Here is my code:
int main() {
typedef struct {
int recordCount;
char *firstName;
char *secondName;
char *id;
char *email;
}student;
student *students = malloc(sizeof(*students));
int i = 0;
while (students[i].firstName[0] != '.'){
students[i].firstName = (char *)malloc(sizeof(char*));
scanf("%s", students[i].firstName);
i++;
students = realloc(students, sizeof(students) * (i + 1));
}
}
When I run it through a for loop it works, I'm pretty sure it's just something silly going on with my while loop.
malloc returns a block of uninitialized memory. So students[i].firstName is an uninitialized pointer which you attempt to dereference. Reading and dereferencing an uninitialized pointer invokes undefined behavior, which in this case manifests as a crash.
When you do allocate space for the firstName member, you only allocate sizeof(char*) bytes for it which is the size of a pointer, not necessarily the length of a string you would want to read.
Create a buffer to read strings into that's big enough for what you might need, then use strdup to create a copy to assign to the relevant pointer.
student *students = NULL;
int i = 0;
char str[100];
scanf("%99s", str);
while (str[0] != '.'){
students = realloc(students, sizeof(*students) * (i+1));
students[i].firstName = strdup(str);
i++;
scanf("%99s", str);
}
For a start,
students[i].firstName = (char *)malloc(sizeof(char*));
allocates enough space for a character pointer, typically four or eight bytes.
While there are some names that will fit in that (such as Pax or Bob), the vast majority probably won't.
You need to allocate enough space for the largest name (and string terminator), such as with:
#define MAX_NAME_LEN 100
students[i].firstName = malloc(MAX_NAME_LEN + 1);
There are plenty of issues in your code.
When you are using malloc, you actually specify the data type and not the pointer type which is I believe is not your intent here. If you are specifying a pointer type with sizeof, the pointer will point to a memory location having the size of the pointer. This is not what you want in this case.
After the line student *students = malloc ... . The students will point to a memory location which will hold zero values in firstName. You need to use malloc for these. Since you are not doing this you are getting a segmentation fault because you are dereferencing an invalid pointer (pointing to location 0). You are trying to access it first and using malloc afterwards.
If you
student *students = malloc(sizeof(*students));
you are allocating size of one pointer. What you want to do is instead
student *students = malloc(sizeof(students));
and for the same reason, students[i].firstName = (char *)malloc(sizeof(char*)) quite surely do not have enough memory for your name as well, try malloc(sizeof(char)*100) or so.
I am trying to accept some values from the user and store them in a char pointer array like so:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *names[3];
char name[20];
int i;
for(i = 0; i < 3; i++) {
printf("Enter your name\n");
scanf("%s", name);
names[i] = (char *)malloc(strlen(name));
names[i] = &name;
// strcpy(names[i], name);
}
printf("Printing the names\n");
for(i = 0; i < 3; i++) {
printf("%s\n", names[i]);
}
}
However, for the following input, I get the following output
Input:
Mark Drew Andrew
Output:
Andrew Andrew Andrew
Why is this happening? When I use the strcpy function I have commented out instead, it seems to work fine.
names[i] = &name; is assigning every element of names to the same character buffer, so only the final version of what's in name will persist in the output.
You need to use strcpy (better still, strncpy) to copy the contents of name to names[i].
And don't forget to call free on every element of names when you're done.
You have memory leak in the code and also assigning the wrong assignment type . correct type assignment would be names[i]=name but still that won't solve the problem. Then also it wont work. You need to use strcpy to store different names. Here you have assigned to names[i] to the same variable - that's why the same output you got.
Note that &name is of type char(*)[20] which you assigned to char*(Compiler warned about this). And for all of the 3 input you got the pointer to array of char which is always the same - so it is pointing to the same array. And now the last value it contained is the input "Andrew". That's what it printed.
So the thing would be
strcpy(names[i],name);
Also scanf should be
if( scanf("%19s",name)!=1 ){
fprintf(stderr,"Error in input\n");
exit(EXIT_FAILURE);
}
malloc's return value should be checked and there is no need for casting.Because void* to char* conversion is implicitly done.
Another easy way would be to use strdup to duplicate the strings.
names[i]=strdup(name);
Also don't forget to free (using free() - this you will have to do in case of strdup also) the dynamically allocated memory when you are done working with it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char *names[3];
char name[20];
for(size_t i = 0; i < sizeof(names)/sizeof(names[0]); i++) {
printf("Enter your name\n");
if(scanf("%19s", name)!= 1){
fprintf(stderr, "%s\n","Error in input" );
exit(EXIT_FAILURE);
}
names[i] = malloc(strlen(name)+1);
if( names[i] == NULL){
perror("malloc");
exit(EXIT_FAILURE);
}
strcpy(names[i],name);
}
printf("Printing the names\n");
for(size_t i = 0; i < sizeof(names)/sizeof(names[0]); i++) {
printf("%s\n", names[i]);
}
for(size_t i = 0; i < sizeof(names)/sizeof(names[0]); i++)
free(names[i]);
return 0;
}
names[0], names[1] and names[2] are pointing to same memory location name, for i=0 Mark will be stored in name for i=1 Drew will be stored and for i=2 Andrew will be stored, so by the end of the loop your array is pointing to name whose value is Andrew
C strings are simple arrays of characters, terminated by a trailing null character. You cannot assign arrays to other arrays, but you can assign them to pointers.
Now by doing names[i] = &name;, you are doing such a pointer assignment. Other than Java or C++ strings, just the address is copied to the pointer, there is no copying of string contents involved (by the way, &name is of bad type: char(*)[20], i. e. a pointer to array of length 20, you need a pointer to char, which you get by simply assigning name directly: names[i] = name;; name decays to a pointer automatically in this case).
The result is that all your string pointers in names point to one and the same character array name, overwriting the pointers to the arrays created by malloc (these are then lost completely, so you cannot free them again either, i. e. you have a memory leak!).
Instead, you have to copy the strings explicitly. However, to not forget the trailing null character:
int len = strlen(name) + 1;
// trailing null char(!): ^^^
names[i] = malloc(len);
memcpy(names[i], name, len);
Notice: using memcpy. Alternatives would have been strcpy or strncpy, but as length (including the trailing null character!) is known anyway, memcpy is most efficient...
Alternative could have been:
names[i] = malloc(20);
scanf("%19s", names[i]);
You spare copying for the price of the arrays potentially being too long. Have a close look on the format string: By adding a maximal length (you need to leave space for the terminating null character again, thus one less!) you prevent the user from writing beyond your buffer (which would be undefined behaviour and potentially lead to crash). If you do not return the array anywhere, even nicer:
char names[3][20];
Edit: Nice alternative, too: strdup (see coderredoc's answer); Two other important points:
always check the result of malloc for being null (memory allocation might have failed! - again see coderredoc's answer).
avoid (further) memory leaks by freeing the created strings again (not with my very last alternative)!
You use names[i] = &name; in every loop iteration, however name gets overwritten with different name, meaning at the end of each iteration, you have all your names[i] (up to the number of iterations so far) all point to name which obviously holds one specific name (which is "Andrew" in your case).
Consider how the memory changes while your code runs:
|--name--| ... |--names[0]--|,|--names[1]--|,|--names[2]--| (loop starting)
|--"Mark"--|...|--points to name, i.e. points to "Mark"--|,|--names[1]--|,|--names[2]--| (1st iteration)
|--"Drew "--|...|--points to name, i.e. points to "Drew "--|,|--points to name, i.e. points to "Drew "--|,|--names[2]--| (2nd iteration)
|--"Andrew"--|...|--points to name, i.e. points to "Andrew"--|,|--points to name, i.e. points to "Andrew"--|,|--points to name, i.e. points to "Andrew"--| (3rd iteration)
Fix this by using strcpy as you mentioned, which will result in:
|--name--| ... |--names[0]--|,|--names[1]--|,|--names[2]--| (loop starting)
|--"Mark"--|...|--copied the value of name, i.e. holds "Mark"--|,|--names[1]--|,|--names[2]--| (1st iteration)
|--"Drew "--|...|--copied the value of name, i.e. holds "Mark"--|,|--copied the value of name, i.e. holds "Drew "--|,|--names[2]--| (2nd iteration)
|--"Andrew"--|...|--copied the value of name, i.e. holds "Mark"--|,|--copied the value of name, i.e. holds "Drew "--|,|--copied the value of name, i.e. holds "Andrew"| (3rd iteration)
Basically, you pointed to variable that changed over time (name) instead of saving it's value (using strcpy)
#note: names[i] = (char *)malloc(strlen(name));should benames[i] = (char *)malloc(strlen(name) + 1);
The line names[i]=&name; doesn't make sense.
You should be getting a compilation error and if you aren't turn on all warnings and errors on your compiler.
It doesn't make sense because names[i] is a pointer to character (char*) and &name is a pointer to a pointer to character (char** or more accurately char(*)[20]).
But changing that to names[i]=name; won't help. It makes names[i] point to the start of the array name. There is only one instance of name. So all elements of names will point to the same location (name) at the end of the loop.
Here's a version with the basic problems fixed:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *names[3];
char name[20];
int i;
for(i = 0; i < 3; i++) {
printf("Enter your name\n");
scanf("%s", name);
names[i] = (char *)malloc(strlen(name)+1);//+1 to include NUL terminator.
strcpy(names[i], name);//Copy name into the space allocated.
}
printf("Printing the names\n");
for(i = 0; i < 3; i++) {
printf("%s\n", names[i]);
free(names[i]);//Release malloc'ed memory after use.
}
}
There's still a security issue that the user can exceed the name buffer by entering more than 19 characters. You should impose a limit on scanf and/or use scanf_s if available using scanf("%19s",name).
The mistake is in the following line ,
names[i] = &name;
it only contact the address of the name string , but it points the last value what the user is input which means it presistant with the last value only .
You must use string copy 'strcpy()' function to copy the input 'name' string in the array of pointer string 'name'.
strcpy(name[i],&name)
#include <stdio.h>
#include <stdlib.h>
struct Album {
char* title;
}
int main(){
int i, size;
struct Album* pAlbum;
printf("Enter the number of album: ");
scanf_s("%d", &size);
pAlbum = malloc(sizeof(pAlbum) * size);
for(i=0; i<size; i++) {
printf("Enter the album title: ");
scanf_s("%p", pAlbum[i].title);
}
free(pAlbum);
return 0;
}
I want to let the user enter the title for as many albums as they want. The error is that scanf only comes up once for pAlbump[i].tittle for the loop. I'm i allocating the memory incorrectly?
pAlbum = malloc(sizeof(pAlbum) * size);
This allocates size pointers. But you wish to allocate size structs.
Your allocation should therefore be
pAlbum = malloc(sizeof(*pAlbum) * size);
or
pAlbum = malloc(sizeof(struct Album) * size);
or
pAlbum = calloc(size, sizeof(struct Album));
Once you've dealt with that, you will need to allocate memory to store each string in the struct. That's going to need separate calls to malloc.
for(i=0; i<size; i++) {
printf("Enter the album title: ");
pAlbum[i].title = malloc(...); // you need to decide how much to allocate
scanf_s("%s", pAlbum[i].title); // hmm, this simply begs a buffer overrun ...
}
And then you'd need to free each of the title strings that you allocated in that loop before freeing the array of structs.
Before using data member title of the structure in statement
scanf_s("%p", pAlbum[i].title);
you have to allocate memory that will be pointed to by this data member and where you are going to store entered data.
And you have to use tag struct before name Album in statement
pAlbum = malloc(sizeof( struct pAlbum) * size);
And instead type specifier "%p" you have to use %s that to enter a string.
First, if you are not to add extra members to your structure then just pull out the char* to the outside and use it. If you want the type to be called Album, you could write typedef char *Album;. You are allocating memory to hold pointers to strings but not the memory that holds the actual strings. Your scanf uses the wrong format %p, use %s to read a string of characters; the scanf is reading to an unallocated piece of memory so that's going to cause a runtime error.
To allocate memory for n items, use calloc (for contiguous allocate). calloc allocates a block of memory for an array of n elements, each of them elem_sizebytes long.
calloc(n, elem_size);
You should know how many bytes each title is or use a maximum number of bytes in your code. There exists a function that will take care of the memory allocation for you but it's not part of the standard. It's called strdup.
You have two options, either make title member an array of fixed size
struct Album {
char title[100];
}
and use scanf_s this way
scanf_s("%99s", pAlbum[i].title, _countof(pAlbum[i].title));
Or, use malloc
char tmp[100];
if (scanf_s("%99s", tmp, _countof(tmp)) == 1)
pAlbum[i].title = strdup(tmp);
Also, to allocate size structs, do as David Heffernan said.
I am making a program that concatenates two strings given by user. Everything is fine, but I don't know why the program shows that the sizeof of the final result is 8-bit long. Doesn't matter how long the strings are, it always shows 8. I guess, that it is the size of char, but I would like to know why it acts this way. This is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* concatenate(char *fir, char *sec)
{
int firLen = strlen(fir);
int secLen = strlen(sec);
int len = firLen + secLen + 1;
int i = 0,c=0;
int *wsk = &i;
char *result = (char *)malloc(len*sizeof(char));
while (fir[i]!='\0')
{
result[i]=fir[i];
(*wsk)++;
}
while (sec[c]!='\0')
{
result[i]=sec[c];
(*wsk)++;
c++;
}
result[len-1] = '\0';
return result;
}
int main(int argc, char **argv)
{
char *first, *second, *output;
int size1, size2;
printf("How long will your first string be: ");
scanf("%d", &size1);
first = (char *) malloc ((1+size1)*sizeof(char));
if (!first)
{
puts("\nError. Can't allocate memory!");
abort();
}
printf("How long will your second string be: ");
scanf("%d", &size2);
second = (char *) malloc ((size2+1)*sizeof(char));
if (!second)
{
puts("\nError. Can't allocate memory!");
abort();
}
printf("\nPlease, type in the first string: ");
scanf("%s",first);
printf("\nPlease, type in the second string: ");
scanf("%s",second);
output = (char *)malloc((size1+size2+1)*sizeof(char));
output = concatenate(first, second);
printf("\nConcatenation of the strings: %s", output);
printf("\n%d", sizeof(output));
free(first);
free(second);
free(output);
getchar();
return 0;
}
Don't use sizeof to determine string length, use the strlen function, as you're doing in other parts of your program.
printf("\nConcatenation of the strings: %s", output);
printf("\n%d", strlen(output));
Use sizeof to determine the size of data types, like char, a struct, an array, etc.
You've mentioned that you want to use sizeof to check if everything is fine with memory allocation, but you can't use sizeof this way on a buffer of memory allocated with malloc: you can only rely on the return value of malloc - which you aren't checking - to know if your allocation was successful.
You can use sizeof to determine the size of an array:
char myStr[13];
printf("%d\n", sizeof(myStr));
But this only works for arrays, and not buffers allocated using malloc.
Also this line creates a memory leak because you overwrite the pointer in the next line:
output = (char *)malloc((size1+size2+1)*sizeof(char));
sizeof gives the size in bytes, where a byte is the size of a char.
printf("\n%d", sizeof(output));
output is a char*, so on your system char*s are 8 bytes large. You must use strlen to obtain the length of a 0-terminated string.
printf("\n%d", sizeof(output)); prints a size of pointer to char. You platform appears to have pointers that are 8 bytes in size.
First:
second = (char *) malloc ((size2+1)*sizeof(char));
Don't typecast the result of malloc().
Second:
sizeof(char) is going to be 1, a char is 1 byte and sizeof() returns the number of bytes required to hold that data type. So you don't need the *sizeof(char), you need that for larger types like int.
Finally:
printf("\nConcatenation of the strings: %s", output); printf("\n%d", sizeof(output));
output is a char * so this is going to give you the sizeof(char *) on your system.
You said in a previous comment:
I know the differences between strlen and sizeof, but using sizeof(output) I wanted to check if everything is fine with memory allocation
Sounds like what you wanted was to verify that you allocated the correct amount of memory for the two concatenated strings. sizeof() won't give you that information. It's in the low level details at this point, you need to do something OS dependent to try and find that information. (ex. in the linux kernel if you kmalloc() memory you can use ksize() to find out exactly how many bytes you got)
I have an assignment I've been working on for a few hours now, and I can't seem to get it quite right. The assignment is to take a random number of names (from stdin), sort them, and then output them in alphabetical order. I can't find any sites online that handle this kind of sorting specifically, and have had no luck trying to implement qsort() into my code.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int stringcmp(const void *a, const void *b)
{
const char **ia = (const char **)a;
const char **ib = (const char **)b;
return strcmp(*ia, *ib);
}
void main(int argc, char *argv[])
{
char *input[] = {" "};
char temp[20][20];
int i = 0;
int num = 0;
int place = 0;
int stringlen = sizeof(temp) / sizeof(char);
printf("How many names would you like to enter? ");
scanf("%d", &num);
while (place < num)
{
printf("Please input a name(first only): ");
scanf("%s", input[place]);
printf("The name you entered is: ");
printf("%s\n", input[place]);
place++;
}
//qsort(temp, stringlen, sizeof(char *), stringcmp); <-- just an idea I was messing with
qsort(input, stringlen, sizeof(char *), stringcmp);
printf("Names:\n");
for(i=0; i<place; i++)
printf("%s\n", input[i]);
system("PAUSE");
return(EXIT_SUCCESS);
}
The main problem is, when I go to output my code, I cannot use the char *input variable because of how its declared. The temp[] will display, but will not be sorted by qsort because it is not declared as a pointer. Any ideas?
You can't declare your input array like that. Since you know how many the user requires, you can dynamically allocate the array:
char **input = malloc(num * sizeof(char*));
Likewise, when you read your strings in, they need somewhere to go. Simply passing an uninitialized pointer to scanf is not okay. I suggest you define the maximum length of a name and have a temporary buffer for reading it:
const size_t MAX_NAME = 50;
char name[MAX_NAME];
...
for( i = 0; i < num; i++ )
{
printf("Please input a name(first only): ");
scanf("%s", name);
input[i] = strdup(name);
}
[Note this does not prevent the user from overflowing the 'name' buffer. I used scanf for illustrative purposes only]
You seem to be passing the wrong array length to qsort. Try this:
qsort(input, num, sizeof(char *), stringcmp);
When you are finished, you need to release memory for all the names and the array.
for( i = 0; i < num; i++ ) free(input[i]);
free(input);
could you explain
the ** declarations throughout the code? I'm not sure what they're
used for, although I know the function for stringcmp is a widely used
algorithm, I have no idea how it works; I'm thrown off by the double
de-reference markers.
Yep, in the case where I used it, I am telling C that to get a single character, I have to dereference a pointer twice. When you index a pointer, it's dereferencing. So I allocated an array by requesting a block of memory containing num * sizeof(char*) bytes. Because I assigned that pointer to a char**, the compiler knows that I am pointing to a chunk of memory that contains char* values.
If I ask for input[0] (this is the same as *input) it should look at the very start of that memory and pull out enough bytes to form a char*. When I ask for input[1], it skips past those bytes and pulls out the next bunch of bytes that form a char*. Etc... Likewise, when I index a char*, I am pulling out single characters.
In your stringcmp function, you have the following situation. You passed a void* pointer to qsort so it doesn't actually know the size of the data values stored in your array. That's why you have to pass both the array length AND the size of a single element. So qsort just blindly rips through this arbitrary-length array of arbitrary-sized values and fires off memory addresses that ought to contain your data for comparison. Because qsort doesn't know anything else about your array elements except where they are located, it just uses void*.
But YOU know that those pointers are going to be the memory addresses of two of your array elements, and that your array elements are char*. So you need the address of a char* (hence you cast the pointers to char**). Now you need to dereference these pointers when you call strcmp() because that function requires a char* (ie a value that points directly to the memory containing your string characters). That is why you use the * in strcmp(*ia, *ib).
One quick way to fix your program is to declare input as an array of pointers, like this:
char *input[20];
When you read names in, use tmp[place] for your buffer, and store the pointer into input, like this:
scanf("%19s", tmp[place]);
input[place] = tmp[place];
Now sorting the input should work fine.
This has a limitation of being limited to 20 lines of 20 characters max. If you learned about malloc in the class, you should be able to fix that by allocating your strings and the string array dynamically.