I wrote this C code to set to NULLan array of structures on C. Here it goes,
struct Worker
{
char name[50];
unsigned int salary;
};
int main()
{
int n;
struct Worker number[50];
for(n=0;n<50;n++)
{
number[n].name=NULL;
}
}
Compiler is giving this error: main.c:65:26: error: assignment to expression with array type.
In your struct, the field name is an array of 50 chars. Arrays are not pointers and you cannot change them; you can only change their contents.
Therefore, if you want to initialise the name field, you could make the name an empty string by making the first char a null terminator:
*number[n].name = '\0';
Note that you name will always hold 50 chars, but you are using only the chars up to the first terminator.
Because your array isn't a pointer, the following doesn't work, either:
number[0].name = "Tom";
You must fill the contents to the array, probably with strcpy from <string.h>:
strcpy(number[0].name, "Tom");
If you want to test whether a string is empty, test whether the first character is the null terminator:
if (*number[n].name == '\0') ... // string is empty
You can also initialise the array explicitly:
struct Worker number[50] = {
{"Alice", 3200},
{"Bob", 2700},
{"Charlotte", 3000}
};
This will give you 3 workers with names and a salary and 47 workers with empty strings as names and zero salary. You can, of course, fill them in later or reset the first three.
If you initialise the array with:
struct Worker number[50] = {{""}};
you'll get an array of all empty-named, all zero-salary workers that you can fill.
(That said, if your name member were a pointer like char *name;, you could say number[n].name = "Tom"; or number[n].name = NULL;. But that would mean that you'd have to handle all the memory that the pointer points to yourself, which is not easy.
The advantage of your array of 50 chars is that each worker has already 50 chars that you can use for their name. (Well, up to 49 plus a null terminator.) The disadvantage is that you waste memory on most names, because they are shorter and you are not flexible enough if you need a name that is longer. But before you have learned more about pointers and memory management, the array is the way to go. Just make sure that you don't exceed its limits.)
You can't set an array of characters to null like that; there's no point. Literally there's no pointer. Arrays aren't pointers; their memory is already allocated on the stack, so I can't redirect the array how you're trying to do it. You're trying to manually set the array's address.
If however your struct looked like this
struct Worker{
char *name;
unsigned int salary;
};
Then you would be able to set each worker's name to null.
If your interest is to zero out an array of characters, you could do this
int n, j;
struct Worker number[50];
for(n=0;n<50;n++)
for(j=0;j<50;j++)
number[n].name[j]=0;
But I have no idea why you'd want to do that. I'm assuming you may use strcpy to assign values to each worker's name, which takes care of the null terminating character for you.
Your name is array of 50 chars, if you want to clear it instead of:
num[n].name=NULL;
do:
memset(num[n].name, 0, 50);
You can set to NULL pointer not the array.
You can see if array is empty by examining each of arrays elem, like:
int i;
int non_empty = 0
for( i=0; i < sizeof(array)/sizeof(array[0]); ++i)
{
if(array[i] != 0)
{
non_empty = 1;
break;
}
}
Related
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char** AllocateShoppingList(int numFoods);
char* AllocateItem();
int DetermineNumberOfCandy(char** list, int numFoods);
int main()
{
char** stringArray;// pointer to pointers
char* words; //pointer to char array
//1. ask the user how many foods are on their list
int foods;
printf("How many foods on the shopping list?\n");
scanf("%d", &foods);
//2. call the AllocateShoppingList function and store the result
stringArray = AllocateShoppingList(foods);
//3. for X times (user's previous input), call the AllocateItem function
// and store the result in the list of pointers (step 2)
for(int i =0;i < foods; i++){
words = AllocateItem();
stringArray[i] = words;}
//strcpy(stringArray[i],words); why not work?
//4. call the DetermineNumberOfCandy function, and print the result
printf("Candy appeared this many times: %d\n",DetermineNumberOfCandy(stringArray, foods));
//5. free up all of the pointers that are held by the shopping list
//6. free up the shopping pointer itself
free(words);
free(stringArray);
}
int DetermineNumberOfCandy(char** list, int numFoods)
{
//0. setup a counter variable
int counter = 0 ;
//1. for each pointer in the shopping list:
//1a. compare the string at the pointer's address to "candy"
for(int i =0; i< numFoods; i++)
if (strcmp(list[i],"candy")==0)
// why you dont have to dereference it
// this concept works with single pointers
// does it work with double or tripple pointers as long as it orignally points to the string?
counter++;
//1b. if it is candy, then tick up the counter variable
//2. return the counter variable
return counter;
}
char** AllocateShoppingList(int numFoods)
{
return calloc(numFoods, sizeof(char*));
//1. allocate memory that can hold X pointers (X = numFoods)
//2. return the memory address holding this pointer to pointers
}
char* AllocateItem()
{
char* wordPtr;
char word[100];
//1. get a word from the user that is max 100 characters
scanf("%s", word);
//2. determine how large the word actually is
wordPtr = calloc(strlen(word)+1,sizeof(char));
strcpy(wordPtr, word);
//3. allocate memory that is just enough to hold the word
return wordPtr;
//4. copy the user's word into the new memory location
//5. return the memory address holding the word
}
**For this code we had to get a shopping last and see print out how many times candy was in the shopping list and in order to do that we had to allocates enough memory to hold onto as many words (strings) as the user wants to have on their shopping list. Then, for each item, allocate just enough memory to store the word. **
This declaration right here for me doesn't make sense
**char** stringArray; **
From what I understand the double pointer is an array which element in the array contains a pointer to the string address.
Because of this I would think that we would have to declare the double pointer like:
char stringArray[]; **
something like this but that would not work.
So I wanted to know how the code knows it is an Array of pointers if we never put brackets
I tried declaring the double pointer with an array and could not get it to work nor could figure out if it was even possible.
Pointers are pointers, arrays are arrays. However, when an array in C is used in an expression or passed as a parameter to a function, it "decays" into a pointer to the first element of that array. This in turn enables things like a pointer arithmetic and the convenient use of the [] index operator.
This also means that in most contexts, a pointer to the first element can be used in place of an array. If we have an array of pointers char* arr[n]; then a char** can be used to point at the first item, and from there on the rest of the array.
So if you'd write a function like int DetermineNumberOfCandy(int numFoods, char* list[numFoods]); that's fine and valid C, but list "decays" into a pointer to the first element anyway, so it is 100% equivalent to
int DetermineNumberOfCandy(int numFoods, char** list);
Also you have misc bugs in your code.
Since AllocateItem is what allocates a valid memory location, the stringArray[i] in main() must be assigned to this memory location before it can be used. Because until then it is just an uninitialized pointer pointing at garbage. Therefore you can't strcpy(stringArray[i], words). Remember that the function did not just allocate a chunk of memory, but also filled it with valid data. So it is sufficient to set the pointer to point at that data, no need to copy anything.
The word variable doesn't fill any purpose, you could as well write this:
for(int i=0; i < foods; i++){
stringArray[i] = AllocateItem();
}
Similarly free(words) is wrong, this would only free the last allocated memory. Rule of thumb: for each malloc call you must have a corresponding free call! Therefore it should be:
for(int i=0; i < foods; i++){
free(stringArray[i]);
}
free(stringArray);
When you declare a variable like a string like this:
char str[10];
Your computer declares in fact a pointer but allocates enough memory to hold 10 characters automaticely. You will see that if you dereference it, you will get the first character of your string.
About your strcpy not working on line 20, if doesnt work because you created your i variable in a for loop and when you do that, the variable disapeers at the end of the loop so you are not able to use it nowhere into your code.
And about your line 40, you can use pointers in at least 2 deferent ways. First one is passing a variabe as a pointer in a function for you to dont have to return it at the end of a function like so:
int main()
{
int var = 0;
my_funct(&var);
//var = 1 now
}
void myfunct(int *var)
{
*var = 1;
}
Here you need to dereference it but if you allocated memory to your pointer, you can now use it as an array without dereferencing it.
Oh and here, you just free one pointer of the 2 in your stringarray. To free everything, try:
for(int i = 0; i < foods; i++) {
free(StringArray[i]);
}
free(StringArray);
Tell me if i didnt awnser to everything or if i was not clear enough
This question already has answers here:
How can I correctly assign a new string value?
(4 answers)
Closed last year.
struct student
{
char name[50];
int rollno;
float marks;
};
int main()
{
char nam[50];
int i = 0, n=5;
struct student s1[n];
for(i=0;i<n;i++)
{
nam[i] = s1[i].name;
}
}
In given code, I am unable to copy s1[i].name in nam[i], I tried all the copy function but it's giving me error every time.
This ...
nam[i] = s1[i].name;
... does not make sense because name[i] is one char, whereas s1[i].name is an array of 50 chars. Moreover, your loop is over the number of elements of s1 (5), which is much less than the number of elements of nam or s1[i].name.
Supposing that you really do want s1 to be an array of struct student as opposed to just one struct, you probably want to use strcpy(). However, you might want or need to use memcpy() (or an element by element copy loop) depending on the nature of the contents of s1 and its elements and any artificial requirements on the exercise.
The strcpy() variation would look like this:
strcpy(nam, s1[i].name);
// do something with nam ...
That depends on the source array to contain a null-terminated string, which is not guaranteed to be the case in the demo program, which never puts any data in s1 or its elements.
Use strcpy() I have tried and it's working
Lots of little things working against you in this code, eg the following...
int i = 0, n=5;
struct student s1[n];
...creates a variable length array of struct student, preventing an initializer from being a viable path. But if for the sake of illustration you can live with a non-VLA version, then try this:
//Use a hard-coded to `5`, to create an array of 5 struct student, initialized as shown:
struct student s1[5] = {{"name1"1, 1.0},("name2",2,2.0},{"name3",3,3.0},{"name4",4,4.0},{"name5",5,5.0}};
Next, your current code: char nam[50]; creates a single uninitialized char array, sufficient for containing only 1 string with up to 49 characters, with a terminating \0. If you can, create it like this. (for the sake of learning to copy strings in a loop.)
char nam[5][50] = {{0}};//created 5 elements of null terminated char array elements,
Then you can do this in your loop:
for(i=0;i<n;i++)
{
strcpy(nam[i], s1[i]name);
}
By now (from comments and answers) you should already know that strings cannot be copied using the = operator like integers or floating numbers. String functions such as strcpy(), or sprintf() can be used to populate strings.
hey I am trying to create a program in which I am trying store elements from one array to another with the use of a pointer to pointer but the problem is that is caused undefined behavior I believe that the problem is that I do not pass the elements in members with a proper way
I know it is a vague way of doing this but It is in only for practising reasons
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct student{
char *name;
int *number;
}T;
int main(void) {
char array[10][100]={"araaaa","bbgt","gffkghgh"};
T arr[10][100];
T *p;
T **p1;
p=&arr[0][0];
p1=&p;
int i=0;
for(i = 0 ; i < 3 ; i++)
{ p=arr[i];
strcpy((*p1)->name,array[i]);
}
/*******print_elements*************/
for(i = 0 ; i < 3 ; i++)
{ p=arr[i];
printf("\n the elements are %s",(*p1)-> name);
}
return 0;
}
When you do this:
strcpy ((*p1)->name, array[i]);
(*p1)->name is an uninitialised pointer. What happens, therefore, is in the lap of the gods.
The easiest fix is to modify your student structure such that name is a buffer, rather than a pointer. At the same time, change number to an int, rather than a pointer to an int::
typedef struct student{
char name [100];
int number;
} T;
If you want to keep name as a pointer then you have to allocate some memory before you store your string in it. This should work:
(*p1)->name = strdup (array[i]);
Don't forget to free the memory when done.
T is made of of two pointers, this first one points to a string of characters in memory.
arr is a 2D array that is allocated to store a total of 1000 T structures.
arr[i] would reference a 1D array of T structures within arr
*p1 would essentially be arr[i], since dereferencing p1 gives you p, which was just set to arr[i]. So, that is not a pointer to a T structure, but to an array of T structures. Forcing the cast will likely give you a reference to the first T structure in that row, however.
->name This value is never set. You allocated an array, but "name" is a pointer to memory, not an array of characters, so '->name' is undefined.
I think you need to change arr to be a single dimension array. You aren't using 90% of it.
And, you need to initialize every T struct in that array. You can use malloc or strdup, and then remember to free them all. Or, set the struct to use an array instead.
I need to make a list of employees and I can't change these structures, I'm having trouble in how to initialize each of tab[10] to NULL and how to set values
#include <stdio.h>
#include <stdlib.h>
typedef struct employee Employee;
struct employee{
char name[81];
float salary;
};
Employee *tab[10]; /*a table with employee*/
void set(Employee **tab, int i, char *name, float salary){
tab[i]->name = name;
tab[i]->salary = salary;
}
int main(){
Employee *e;
int i = 0;
for(; i < 10; i++) init(i,&e);
return 0;
}
/*a table with an employee, each position must have a name and a salary*/
Employee *tab[10];
void init(int n, Employee **tab);
Everaldo
With commentators helping you, it seems you are getting there. I would like to sum up the suggests given so far and add a couple of my own.
Declaring the Employee array
Declaring the array as a global variable and then passing it as a parameter to functions makes things a little confusing. I usually prefer declaring a local variable and then passing it to the various functions that uses it. Also as suggested by David C. Rankin, to initialize every array element to 0 just requires you to initial the first element in the declaration statement. No FOR loop needed. The compiler will auto initialize the rest of the array elements for you.
main()
{
Employee* tab[10] = { NULL };
. . . .
}
Array memory allocation
As mention by Patrick87, you need to add code to assign memory to every element in the array. An example initialization routine could be coded as follows:
int init(int len, Employee** tab) {
int i = 0;
for (i = 0; i < len; i++)
{
if ( (tab[i] = (Employee*) calloc (1,sizeof(Employee))) == NULL )
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Function usage:
if (init(10, &tab) == EXIT_FAILURE)
{
puts("CALLOC Failed, aborting....");
exit(EXIT_FAILURE);
}
Things to note:
Check to ensure the memory was allocated. On failure return some
type of failure status to alert the caller of the function.
The status codes that are being returned are define in stdlib.h.
They are not necessary but do give a clear indication to the reader
of your code the success and failure paths your code takes.
The FOR loop was moved inside the initialization function. Function
calls are expensive when it comes to processing time. Since the
array size is known, it is faster to perform the loop inside the
function.
Try to always write functions that return a status. This will enable
the caller to perform any error handling if the function's operations
fail.
Set array element values
The following statement is not valid. You cannot directly copy the content from a string pointer to an array of characters. You will need to use statements like strcpy, strncpy, or memcpy to copy the data.
tab[i]->name = name;
There is a method I prefer for copying strings.
sprintf(tab[i]->name, "%.80s", name);
This will copy up to 80 characters from name into tab[i]->name, then insert a null character. The beauty of this statement is that the designation variable does not have to be the same size as the source. If the source variable (in this case name) is shorter, spirntf will simply stop when it encounter a null character and then null terminate the destination string. If the source is longer than 80 characters or if it is missing the null terminator character, sprintf will stop coping at the 80st character position and then auto insert a null character in the 81st character position.
An example SET routine could look like the following:
void set(Employee** tab, int i, char* name, float salary) {
sprintf(tab[i]->name, "%.80s", name);
tab[i]->salary = salary;
}
Usage:
for (i = 0; i < 10; i++)
{
set(&tab, i, "Bob", 35000. + i); // bogus values, demo purposes only
}
Main program logic
Your main program as you currently have outline will need to change. For starters, the declaration of variable “e” should be replace with the declaration of variable “tab” (see Patrick87 comments) . On initializing the array, see my suggestion above. To set values to the array elements see SET function comments above.
Free memory
Every time you allocate memory, you must free it when you are done. Forgetting to free allocated memory will create memory leaks in your program. Note technically, in this demonstration program, the system will free the memory when your code exits, so you do not need to free it. But it is good practice so when you start writing real applications you will not forget to do so.
Here is an example on how this could be done:
for (i = 0; i < 10; i++)
free (tab[i]);
tab is an array of pointers, so to initialize them all to NULL, you can use a for loop, e.g.
for (i = 0; i < n; i++)
tab[i] = 0;
To set a value, allocate some space for an instance of your struct (either on the stack via function parameter or local variable, or else on the heap by with malloc/calloc/realloc) and then set one of the tab[k] to the address of the memory you allocated (using & or just the pointer directly if allocated).
Okay so that wasn't very clear. What I am trying to do is this:
while (//something) {
char * tempuser;
char * users[100];
tempuser = "bobsmith" //I'm not actually doing this. But using a method that does the same thing
users[i] = tempuser;
}
Where "bobsmith" is is different everytime through the loop. If I run this, as is, 5 times and the last entry is "janetsmith" all 5 places in the array before that, regardless of being different when assigned, all end up as "janetsmith". How should I assign users[i] so that it has a different value in all indexes?
Do not create the array users in loop body, and use strdup to create new string with the same content inside the array. Remember that You are using pointers not some kind of string objects. Each entry in array holds the address of the text inside memory.
char *users[100]={0}; //one hundred pointers that are null so You don't use a wild one.
int i=0;
while(/*whatever*/) {
char *tmp=getsometext(); //returns char pointer
users[i++]=strdup(tmp); //copies contents pointed by tmp into new memory location and returns its address
}
//don't forget to free every pointer when You are done.
It is because you are assigning address of the variable tempuser. By the end of it all, it will always hold the address of "janetsmith". Try creating the variable dynamically using malloc() function.
char * users[100]; //with this you can use it outside while
while (//something) {
static unsigned int i = 0;
//char * tempuser;
//tempuser = "bobsmith" //I'm not actually doing this. But using a method that does the same thing
users[i] = method_which_return_char_pointer();
i++;
if( 100 <= i)
i=0;
}
this what from your brief Question explanation .