Modifying strings in a string array in C - c

this is my problem... I created an array of strings like this..
char *name[12];
Then the user types 12 different names so I can save them in that array. But it is known that if you don't initialize a variable it has 'garbage' in it. So I started saving the names correctly until the 5th name, then it crashes, I don't know why. So I tried to initialize every element but then it doesn't allow me to change the content.
This is how I write into every element of the array:
printf("Type your name: ");
fflush(stdin);
gets( name[0] ); //I use a for to move into every element
And I want to know if there's any way to initialize the array, and to change it's content after that. I've tried with strcpy(); but I had the same error. Or how to delete that 'garbage' to stop it from causing me errors.
Thanks, and sorry if I had any misspelling. English is not my native language.

You've allocated space for 12 pointers; you've never allocated the space for the 12 strings, let alone assigned the pointers to that space to the pointers in the array.

The problem is that you have your array of char pointers, but you haven't initialised them or allocated space for them in any way. So you don't know what will happen when you use the address it points to.
You would have to loop through the array and initialise the elements before you can use them.
name[0] = malloc (SIZE);
You can try reading user input to a buffer to get the length of the data entered, then mallocating just the correct amount of space, or having a pre-defined chunk of memory to allocate before using it.

Related

Using strcpy on a 2D char array allocated with malloc

I have a problem, and I cannot figure out the solution for it. I have to programm some code to a µC, but I am not familiar with it.
I have to create an analysis and show the results of it on the screen of the machine. The analysis is allready done and functional. But getting the results from the analysis to the screen is my problem.
I have to store all results in a global array. Since the stack is really limited on the machine, I have to bring it to the larger heap. The linker is made that way, that every dynamic allocation ends up on the heap. But this is done in C so I cannot use "new". But everything allocated with malloc ends up on the heap automatically and that is why I need to use malloc, but I haven't used that before, so I have real trouble with it. The problem with the screen is, it accepts only char arrays.
In summaray: I have to create a global 2D char array holding the results of up to 100 positions and I have to allocate the memory for it using malloc.
To make it even more complicated I have to declare the variable with "extern" in the buffer.h file and have to implement it in the buffer.c file.
So my buffer.h line looks like this:
extern char * g_results[100][10];
In the buffer.c I am using:
g_results[0][0] = malloc ( 100 * 10 )
Each char is 1 byte, so the array should have the size of 1000 byte to hold 100 results with the length of 9 and 1 terminating /0. Right?
Now I try to store the results into this array with the help of strcpy.
I am doing this in a for loop at the end of the analysis.
for (int i = 0; i < 100, i++)
{
// Got to convert it to text 1st, since the display does not accept anything but text.
snprintf(buffer, 9, "%.2f", results[i]);
strcpy(g_results[i][0], buffer);
}
And then I iterate through the g_results_buffer on the screen and display the content. The problem is: it works perfect for the FIRST result only. Everything is as I wanted it.
But all other lines are empty. I checked the results-array, and all values are stored in them, so that is not the cause for the problem. Also, the values are not overwritten, it is really the 1st value.
I cannot see what it is the problem here.
My guesses are:
a) allocation with malloc isn't done correctly. Only allocating space for the 1st element? When I remove the [0][0] I get a compiler error: "assignment to expression with array type". But I do not know what that should mean.
b) (totally) wrong usage of the pointers. Is there a way I can declare that array as a non-pointer, but still on the heap?
I really need your help.
How do I store the results from the results-array after the 1st element into the g_results-array?
I have to store all results in a global array. Since the stack is really limited on the machine, I have to bring it to the larger heap.
A “global array“ and “the larger heap” are different things. C does not have a true global name space. It does have objects with static storage duration, for which memory is reserved for the entire execution of the program. People use the “heap” to refer to dynamically allocated memory, which is reserved from the time a program requests it (as with malloc) until the time the program releases it (as with free).
Variables declared outside of functions have file scope for their names, external or internal linkage, and static storage duration. These are different from dynamic memory. So it is not clear what memory you want: static storage duration or dynamic memory?
“Heap” is a misnomer. Properly, that word refers to a type of data structure. You can simply call it “allocated memory.” A “heap” may be used to organize pieces of memory available for allocation, but it can be used for other purposes, and the memory management routines may use other data structures.
The linker is made that way, that every dynamic allocation ends up on the heap.
The linker links object modules together. It has nothing to do with the heap.
But everything allocated with malloc ends up on the heap automatically and that is why I need to use malloc,…
When you allocate memory, it does not end up on the heap. The heap (if it is used for memory management) is where memory that has been freed is kept until it is allocated again. When you allocate memory, it is taken off of the heap.
The problem with the screen is, it accepts only char arrays.
This is unclear. Perhaps you mean there is some display device that you must communicate with by providing strings of characters.
In summaray: I have to create a global 2D char array holding the results of up to 100 positions and I have to allocate the memory for it using malloc.
That would have been useful at the beginning of your post.
So my buffer.h line looks like this:
extern char * g_results[100][10];
That declares an array of 100 arrays of 10 pointers to char *. So you will have 1,000 pointers to strings (technically 1,000 pointers to the first character of strings, but we generally speak of a pointer to the first character of a string as a pointer to the string). That is not likely what you want. If you want 100 strings of up to 10 characters each (including the terminating null byte in that 10), then a pointer to an array of 100 arrays of 10 characters would suffice. That can be declared with:
extern char (*g_results)[100][10];
However, when working with arrays, we generally just use a pointer to the first element of the array rather than a pointer to the whole array:
extern char (*g_results)[10];
In the buffer.c I am using:
g_results[0][0] = malloc ( 100 * 10 )
Each char is 1 byte, so the array should have the size of 1000 byte to hold 100 results with the length of 9 and 1 terminating /0. Right?
That space does suffice for 100 instances of 10-byte strings. It would not have worked with your original declaration of extern char * g_results[100][10];, which would need space for 1,000 pointers.
However, having changed g_results to extern char (*g_results)[10];, we must now assign the address returned by malloc to g_results, not to g_results[0][0]. We can allocate the required space with:
g_results = malloc(100 * sizeof *g_results);
Alternately, instead of allocating memory, just use static storage:
char g_results[100][10];
Now I try to store the results into this array with the help of strcpy. I am doing this in a for loop at the end of the analysis.
for (int i = 0; i < 100, i++)
{
// Got to convert it to text 1st, since the display does not accept anything but text.
snprintf(buffer, 9, "%.2f", results[i]);
strcpy(g_results[i][0], buffer);
}
There is no need to use buffer; you can send the snprintf results directly to the final memory.
Since g_results is an array of 100 arrays of 10 char, g_results[i] is an array of 10 char. When an array is used as an expression, it is automatically converted to a pointer to its first element, except when it is the operand of sizeof, the operand of unary &, or is a string literal used to initialize an array (in a definition). So you can use g_results[i] to get the address where string i should be written:
snprintf(g_results[i], sizeof g_results[i], "%.2f", results[i]);
Some notes about this:
We see use of the array both with automatic conversion and without. The argument g_results[i] is converted to &g_results[i][0]. In sizeof g_results[i], sizeof gives the size of the array, not a pointer.
The buffer length passed to snprintf does not need to be reduced by 1 for allow for the terminating null character. snprintf handles that by itself. So we pass the full size, sizeof g_results[i].
But all other lines are empty.
That is because your declaration of g_results was wrong. It declared 1,000 pointers, and you stored an address only in g_results[0][0], so all the other pointers were uninitialized.
This is all odd, you seem to just want:
// array of 100 arrays of 10 chars
char g_results[100][10];
for (int i = 0; i < 100, i++) {
// why snprintf+strcpy? Just write where you want to write.
snprintf(g_results[i], 10, "%.2f", results[i]);
// ^^^^^^^^ has to be float or double
// ^^ why 9? The buffer has 10 chars.
}
Only allocating space for the 1st element?
Yes, you are, you only assigned first element g_results[0][0] to malloc ( 100 * 10 ).
wrong usage of the pointers. Is there a way I can declare that array as a non-pointer, but still on the heap?
No. To allocate something on the heap you have to call malloc.
But there is no reason to use the heap, especially that you are on a microcontroller and especially that you know how many elements you are going to allocate. Heap is for unknowns, if you know that you want exactly 100 x 10 x chars, just take them.
Overall, consider reading some C books.
I do not know what that should mean.
You cannot assign to an array as a whole. You can assign to array elements, one by one.

Can I have an array with indeterminate length in C?

so I am a beginner in c, and I am doing this program where a user input values in an array and if the value is 101 then the program is finished. the thing is I don't want the length of the array to be initialized, rather when the user enter 101 there would be the last value and the last place in the array. for example they entered 101 in the third place then the length of the array would be 4. I don't know if that possible.
#include <stdio.h>
int main(void) {
int i,j;
int a[i];
for(i=0;i<10;i++)
{
printf("Enter Value Nummber %d:",i);
scanf("%d",&a[i]);
if
(a[i] == 101) break;
else continue;
}
Here I put the max length could be 10 but, if the user for example gives just 4 values and then 101 then it gives the rest of spots garbage values.
In this case
int a[i];
is called a variable length array, and you're using i unitialized, and that can invoke undefined behaviour. You need to have a defined value of i before you can use it.
That said, the cleaner approach will be (without using dynamic allocation and re-sizing)
Define a higher limit (#define MAXLEN 100) and use that to create an array, and initialize it to a value (say, 0).
Keep on asking user for the inputs, until (whichever is earlier)
You get a value 101
Counter reaches MAXLEN
Otherwise, if you're okay with using allocated memory (malloc()/ realloc() and family), then:
Define a starting size (#define INITSIZ 32)
Allocate memory for that size using malloc().
Ask user for inputs.
If you get an input value of 101, free() the allocated memory and exit.
Otherwise, once you hit the size, double the allocation using realloc() and continue to previous step.
I recommend having a look at malloc. It allows you to dynamically allocate memory and gives you a pointer to the start of the allocated piece of memory.
You can access an element with a pointer that points to the first element and then increase the pointer every time you add a value. Unlike other languages, C does not prevent you from accessing values outside of an array, so track the number of items added with a counter, and make sure to stay within your allocated memory (so save the length in a variable). You can then replace the for loop with an infinite loop, and break once the user inputs the value 101. When you reach the limit of your allocated memory, you can allocate a new array twice the size (so make sure to save the length in a variable) and copy the previous array there, then free the first array.
"Can I have an array with indeterminate length?"
I don't want the length of the array to be initialized, rather when the user enter 101 there would be the last value and the last place in the array. For example they entered 101 in the third place then the length of the array would be 4. I don't know if that possible.
No, it is not possible.
int a[i];
You cannot write to an indeterminate array, as i is not initialized - it holds a garbage value.
Any such attempt is undefined behavior and doesn´t make much sense.
How do you want to store the value the user puts in to the assumed third element if there has not been space allocated for it?
Of course you can use VLAs or allocate and reallocate dynamic memory (as the other two answers suggest) but you can´t write data to memory which isn´t allocated for storing that values.
I do not understand your idea behind. Maybe you explain the bigger goal you want to achieve.

Having issues with understanding Array Size

#include<stdio.h>
int main ()
{char c[5];
scanf ("%s",&c);
printf("%s",c);}
So I have declared the array size to be 5.
But lets say when I type Elephant which is an 8 lettered word it still gets printed.Can someone explain why and also suggest what I should do so that the computer takes/considers my input only upto 5 characters.
This is non-deterministic behavior. The array is 5 characters in memory, but scanf is not safe. It is putting all 8 characters into sequential memory starting at c[0] although 3 of the characters are technically not part of the array c. The last three characters may end up getting changed by some other application or function because they are not owned by the array c.
If you use the proper scan_s function it will throw an error when you try to do this. You should always use the "safe" functions for this.
Any array like this is actually a pointer to the first element of the array and the [5] indicates a 5 memory location offset from the first memory location defined by "c". You can freely set the number inside [] to any offset although it may go outside the bounds of what you allocated to c.
In C, arrays have no bound-check. So basically, if you declare a 5-element array, you could store 100 elements in it and, if you are lucky (here, by lucky I mean to not overwrite some other, important things, that affect the program execution), it will work. But it is dangerous and wrong. It's your responsibility to make sure this will not happen.
the variable c is allocated into the stack, when allocating space into the stack, the compiler may allocate more than what you're function really need so, that why when you write 8 character into the stack of the function main, you don't receive a segmentation fault.
you should change you're code and use :
fgets(c, sizeof c, stdin);

how test if char array is null?

I've been doing (in C)
char array[100];
if (array == NULL)
something;
which is very wrong (which I have finally learned since my program doesn't work). What is the equivalent where I could test a new array to see if nothing has been put in it yet?
Also, how do you make an array empty/clean it out?
I know there are other posts out on this topic out there, but I couldn't find a straightforward answer.
An array declared with
char array[100]
always has 100 characters in it.
By "cleaning out" you may mean assigning a particular character to each slot, such as the character '\0'. You can do this with a loop, or one of several library calls to clear memory or move memory blocks.
Look at memset -- it can "clear" or "reset" your array nicely.
If you are working with strings, with are special char arrays terminated with a zero, then in order to test for an empty array, see this SO question. Otherwise if you have a regular character array not intended to represent text, write a loop to make sure all entries in the array are your special blank character, whatever you choose it to be.
You can also declare your character array like so:
char* array = malloc(100);
or even
char* array = NULL;
but that is a little different. In this case the array being NULL means "no array has been allocated" which is different from "an array has been allocated but I have not put anything in it yet."

Array Elements Overwritten with Last in C

I'm trying to create a program which takes in a set number of strings (the user is asked to put in the number of strings they will enter), once it has these strings, they are placed in an array, using dynamic memory.
The ouput would be something like this:
# of Strings: 3
Cat
Dog
Elephant
Cat
Dog
Elephant
Heres a snippet of my code, after I have the number of strings.
sptr=malloc(sizeof(char*)*nStrings);
for(i=0;i<nStrings;i++)
{
scanf("%s",string);
length=strlen(string);
sptr[i]=malloc(sizeof(char)*length);
sptr[i]=string;
}
Where sptr is the array I'll access to output the strings.
So it's an array of pointers which then point to individual strings (or other arrays of characters, if you'd prefer to think of it that way).
Lets say there are two strings.
I allocate memory for two pointers,
Then in the first pointer, i scan in a string,
i find the length of the string,
i allocate memory the size of the string
and i equal the pointer to the string.
This all works dandy, and if I were to put a printf() right after that last line, it will work.
The problem i face is, if lets say there are 3 strings, each time through sptr[i] is assigned correctly, but then outside of that block, all of the indicies of sptr are = to the last string i put in, and I have no idea why.
If you could help me out I'd appreciate it. Thanks.
sptr=malloc(sizeof(char*)*nStrings);
for(i=0;i<nStrings;i++)
{
scanf("%s",string);
sptr[i]=strdup(string);
}
I assume the variable string has enough memory to keep the read strings.
The error occured because you set the pointer to point to the string variable.
You need to allocate 1 character extra for the null terminator:
sptr[i]=malloc(sizeof(char)*(length+1));
Also, you need to copy the string into the newly allocated memory:
strcpy(sptr[i], string);
There are 2 problems in your code: you don't allocate enough memory. Should be length + 1 because of the ending \0 in a string. Secondly you should use strcpy to copy the string to your allocated memory. Lookup the strdup function that handles both.
strlen doesn't account for the zero termination, you need to add one. But mainly you need to copy the string into the memory you allocate.

Resources