storing char* array in C - c

I'm trying to create and store a char* array.
So, first I tried this:
int main() {
char* values[3];
values[0] = "Hello";
values[1] = "Mew meww";
values[2] = "Miau miau =3";
for(int i=0; i<sizeof(values); i++)
printf("%s", values[i]);
}
it works with this OUTPUT:
Hello
Mew Mew
Miau miau =3
If i try:
printf("%s", "Tamaño del diccionario: ");
int tam;
scanf("%i", &tam);
char* dic[tam];
Word words[tam];
for(int i=0; i<tam; i++)
{
printf("Palabra %d: ",(i+1));
scanf("%32s", &dic[i]);
}
for(int i=0; i<tam; i++)
{
printf("%s",dic[i]);
printf("\n");
}
Show non-legible stuff like "0xassdfsdf"
What can I do to store it right in memory?

#include <stdio.h>
#include <stdlib.h>
int main(){
char* values[3];
values[0] = "Hello";
values[1] = "Mew meww";
values[2] = "Miau miau =3";
for(int i=0; i<sizeof(values)/sizeof(*values); i++)
printf("%s\n", values[i]);
printf("%s", "Size for dictionary: ");
int tam;
scanf("%i", &tam);
char *dic[tam];
for(int i=0; i<tam; i++){
printf("Palabra %d: ",(i+1));
dic[i] = malloc(33);
scanf("%32s", dic[i]);
}
for(int i=0; i<tam; i++){
printf("%s\n", dic[i]);
free(dic[i]);
}
return 0;
}

One problem is
scanf("%32s", &dic[i]);
which should be
scanf("%32s", dic[i]);
because the array contains pointers to storage, not storage itself, and what you should pass to scanf is this pointer. Indeed, a char* is just a 4-byte pointer. The array char* dic[tam] contains some such pointers, so that dic[0] is a 4-byte pointer to char, and &dic[0] is the address of this pointer. Then your
scanf("%32s", &dic[i]);
just overwrites this pointer plus corrupts memory after it.
Another problem is that you do not initialize the array, so it does not point to any storage.
char* dic[tam];
here the array contains pointers to random places in memory.
scanf("%32s", &dic[i]);
most probably this fails at all. So in your printf you print pointers to random places in memory.
A (bad) solution is:
for(int i=0; i<tam; i++)
{
printf("Palabra %d: ",(i+1));
dic[i] = new char [1000]; // here you assign it some storage
scanf("%32s", dic[i]); // NOT &dic[i]
}
or (slightly better)
for(int i=0; i<tam; i++)
{
printf("Palabra %d: ",(i+1));
char buffer [1000]; // temporal storage arguably large enough
scanf("%32s", buffer);
dic[i] = new char [strlen (buffer) + 1]; // storage of the right size to hold the string
strcpy (dic[i], buf); // copy the data to this new storage
}

The key thing to understand for both of your examples is that a char * value stores the address of a byte in memory. By convention, C strings are represented as a pointer to the first byte of the string, with a null byte marking the end. When you assigned constant strings into your array, the compiler allocated the necessary memory and placed the pointers into your array, but when you are not using constants it is your responsibility to allocate the buffer to store the string, and then store that pointer in the array yourself.
In your second example you have allocated storage for several pointers to char, but you have not made those pointers refer to valid buffers, so accessing them with either return garbage or crash the program. There are (at least) two ways to address this: either allocate a fixed-size buffer on the stack and store your data there, or dynamically allocate memory from the heap using malloc.
The former has the advantage of handling the deallocation of the buffers automatically, but requires you to decide at compile time how much memory to allocate for each string:
char* dic[tam];
char buf[tam * 32]; // allocate 32 bytes per element.
for (int i = 0; i < tam; i++) {
// Make the pointers in ``dic`` refer to 32-byte offsets into the buffer.
dic[tam] = &(buf[tam * 32]);
}
You can also allocate dynamically using malloc. You could actually allocate one big tam * 32 buffer this way too, but for the sake of example here's how to allocate a separate buffer for each element:
char* dic[tam];
for (int i = 0; i < tam; i++) {
// Allocate 32 bytes per element.
// (This value can be decided at runtime, if you want.)
dic[tam] = malloc(32);
}
But since this uses malloc you need to be sure to clean up this memory before you return to avoid a memory leak. e.g. at the end of your routine:
for (int i = 0; i < tam; i++) {
// de-allocate the buffer we allocated earlier
free(dic[tam]);
}
(This method of calling malloc multiple times in a loop may also cause memory fragmentation if you do it a lot, but that's an advanced topic not worth worrying about for a small program.)

Related

How do I allocate an array of string in an array of structure

I'm trying to allocate the char** path array in my batiment struct
#ifndef SDL2_BATIMENTS_H
#define SDL2_BATIMENTS_H
typedef struct{
int x;
int y;
}vecteur;
typedef struct{
int numtype; //Détermine quelle representation du batiment (route nor/ route sud...)
char** tabpath; // tableau de chemin d'acces aux images
vecteur size; // Taille du batiment en (x,y)
int habitant;
}batiment;
typedef struct {
vecteur** tuile;
batiment* tabbatiment; //tableau de batiment
}Monde;
Monde* InitBatiment(Monde* monde);
vecteur toGrid(float x,float y);
#endif //SDL2_BATIMENTS_H
I've tried to allocate it like an array[][], at first it seems to be working with no error but everytime i try to access it my program crashes
for(int i=0; i<14;i++)
{
monde->tabbatiment[i].tabpath = malloc(7 * sizeof (char*));
for (int y = 0; y < 7; y++)
monde->tabbatiment[i].tabpath[i] = (char*)malloc(50 * sizeof(char));
}
Ok First of all thank you for your answer, I changed my code to this but everytime my program try to call strcpy it crashes.
I think I still have an allocation problem or a memory leak.
for(int i=0; i<14;i++)
{
monde->tabbatiment[i].tabpath = calloc(10,sizeof(char*));
for(int y = 0; y < 10; y++)
monde->tabbatiment[i].tabpath[i] = calloc(30 ,sizeof(char));
}
FILE *f;
char c;
int numbatiment;
f=fopen("batiment.txt","r");
int x,y,numbat,numtype;
const char path[50];
for(int i =0;i<16;i++)
{
fscanf(f,"%d %d %d %d %s ",&numbat,&x,&y,&numtype,&path);
printf("%s",path);
strcpy(monde->tabbatiment[numbat].tabpath[numtype],path);
monde->tabbatiment[numbat].size.x = x ;
monde->tabbatiment[numbat].size.y=y ;
monde->tabbatiment[numbat].numtype = numtype;
printf("%d %d %d %d %s\n",numbat,monde->tabbatiment[numbat].size.x,monde->tabbatiment[numbat].size.y,monde->tabbatiment[numbat].numtype,monde->tabbatiment[numbat].tabpath[numtype]);
}
fclose(f);
Could you elaborate what you are exactly trying to accomplish with the code? It feels like there is more to it then a simple bug, but more of an implementation issue as a whole.
I cannot replicate your SEGFAULT for what it's worth. I do run into a lot of memory issues in valgrind, all of which could be attributed that you allocate memory in a loop, where you could've easily done it in a linear block (hence why I'm afraid that there might be more to this).
To directly answer your question: allocating memory for a string can go 2 ways: either you allocate enough memory from the start for which you are certain the any string you throw at it will be smaller than the allocated memory. Or you allocate memory on the go based on the length of the string that you are adding to your array.
In both cases you would be looking at a combination of malloc/calloc and strcpy/strncpy (the latter in both having my preference most often). Allocate memory where the string should reside, than copy a local buffered value to the designated memory address.
Anyway, I've refactored your example to this. I have to say: take a GOOD look at how you are using indexes in loops. You are going out of bounds often, which might trigger a SEGFAULT. For monde->tuile for instance you allocate 35 slots, but the next thing you do is loop the tuile index to 44. I've also included some define statements which are good practice over magic numbers.
#define SIZE_BATIMENT 15
#define SIZE_TUILE 34
#define SIZE_TABPATH 8
#define MAX_STRING_LEN 64
Monde *monde = calloc(1, sizeof monde);
monde->tuile = calloc(SIZE_TUILE, sizeof(vecteur *));
for (int i=0 ; i <= SIZE_TUILE ; i++)
{
monde->tuile[i] = (vecteur*)malloc(45 * sizeof(vecteur));
}
// Assign memory to allow MAX_STRING_LEN sizes
monde->tabbatiment = calloc(SIZE_BATIMENT, sizeof(batiment));
for(int i = 0; i <= SIZE_BATIMENT; i++)
{
monde->tabbatiment[i].tabpath = calloc(SIZE_TABPATH, sizeof(char *));
for (int j = 0; j <= SIZE_TABPATH; j++)
{
monde->tabbatiment[i].tabpath[j] = calloc(MAX_STRING_LEN, sizeof(char));
}
}

how to allocate arrays (in array of pointers) C -- can it be done in one line? with malloc

is there a simple one liner I can use in C to allocate arrays in (pointer of arrays)
This line creates 10 pointers of arrays
char *out[10];
I can't do this
char *out[100]=(char[10][100])malloc(sizeof(char)*10*100);
error: cast specifies array type
same error with
char *out[10]=(char*[10])malloc(sizeof(char)*10*100);
do I need to do it in loop like this
int main()
{
char *out[10];
int x=0;
while(x<10)
{
*(out+x)=malloc(sizeof(char)*100);// is this line correct?
x++;
}
*out[0]='x';
printf("%c\n",out[0][0]);
free(out);
return 0;
}
but this cause warning that
req.c:75:3: warning: attempt to free a non-heap object ‘out’ [-Wfree-nonheap-object]
75 | free(out);
so do I need to allocate and free each array in (array of pointers) in loop
Can't I do allocation and free arrays in array of pointer in one line instead of loop?
or is there anything thing in my loop wrong too
To allocate an array of pointers to strings, you need to do:
char** out = malloc(sizeof(char*[10]));
The whole point of using this form is that each pointer in that array of pointers can be allocated with individual size, as is common with strings. So it doesn't make sense to allocate such with a "one-liner", or you are using the wrong type for the task.
In case you don't need individual sizes but are rather looking for a char [10][100] 2D array with static size, then the correct way to allocate such is:
char (*out)[100] = malloc(sizeof(char[10][100]));
You can allocate the full array in one single step and have pointers inside that array:
char *out[10];
data = malloc(100); //sizeof(char) is 1 by definition
for (int x=0; x<10; x++) {
out[i] = data + x * 10;
}
*out[0] = 'x';
printf("%c\n",out[0][0]);
free(data); // you must free what has been allocated
int i;
char** out = (char**)malloc(sizeof(char*)*10);
for(i = 0; i<10;i++)
out[i] = (char*)malloc(sizeof(char)*100);
out[1][1] = 'a';
OR with same dimensions
#include <stdio.h>
#include <stdlib.h>
void main()
{
int r = 10, c = 100; //Taking number of Rows and Columns
char *ptr, count = 0, i;
ptr = (char*)malloc((r * c) * sizeof(char)); //Dynamically Allocating Memory
for (i = 0; i < r * c; i++)
{
ptr[i] = i + 1; //Giving value to the pointer and simultaneously printing it.
printf("%c ", ptr[i]);
if ((i + 1) % c == 0)
{
printf("\n");
}
}
free(ptr);
}

2D array as pointer to char array

I am playing with some code in C and also I am trying to understand relationship between pointers and arrays. As you probably know, when I want to make array it could be done like this:
char * arr = "abc";
or
char arr[] = {'a','b', 'c'};
But when I want to do 2D array. It must be done like this
char arr[3][10];
Why declaration like this crashes when I try to load string to that.
char * names[3];
for ( int i = 0; i < 3; i++ ) {
printf("Enter name %d: ", i+1 );
scanf("%s", names[i]);
}
// print names
printf("\nEntered names are: \n");
for ( int i = 0; i < 3; i++ ) {
printf("%s\n", names[i] );
}
It should be 2D array right? Because array is basically pointer.
Could you please explain that?
Thanks.
char * names[3];
Is not a 2D array, it's an array of three pointers to char, if you want to store char arrays in it you must allocate memory to each individual pointer, something like:
for(size_t i = 0; i < 3; i++){
names[i] = malloc(/*length your array of chars*/);
}
You can then store char arrays, using you example:
for(size_t i = 0; i < 3; i++){
printf("Enter name %ld: ", i + 1 );
scanf("%29s", names[i]); //for a malloc size of 30
}
Note that you must be careful with scanf, if the inputed string is longer then the memory allocated to store it you will have stack smashing, i.e. for names[i] with size of 30, you should use %29s specifier, instead of %s. Though this approach is not whitout its issues, namely possible characters left in stdin buffer, it's definitely safer.
Alternatively you can assign them string literals (in this case it's best to declare the array as const, otherwise if you try to edit one or more characters it'll result in a segfault):
const char* names[3];
for(size_t i = 0; i < 3; i++){
names[i] = "My string literal";
}
You can also make them point to existing char arrays:
char arr[3][10];
char* names[3];
for(size_t i = 0; i < 3; i++){
names[i] = arr[i];
}
char * names_1[3];
It's not a pointer. It's an array of pointers.
char names_2[3][10]={"one", "two", "three"};
char (*p_names_2)[10]=names_2;
Now it's a pointer to your 2D-Array. Just define a function and try to use it with your "pointers" as parameters.
void print_names(char names[][10], const int row){
for(int i=0; i<row; i++)
puts(names[i]);
}
Now call it with:
print_names(names_2, 3);
print_names(p_names_2, 3);
print_names(names_1, 3); //WRONG
And you'll see the difference.
char* names[3] is not strictly a 2D array (they don't exist in C or C++); it's an array of arrays. So each element of names contains simply a char*, which has not been initialised.
Note also that a c-style string is a null-terminated array of chars, so your original arr is not a c-style string. To make it a c-style string you would need:
char arr[] = {'a','b','c',0};
making it an array of length 4, not 3.
Missing off the null-terminator will mean that most functions will run off the end of the allocated memory, because they won't know when the string stops.
pointer is a type of variable, which can only contain an address of another variable. It can't contain any data. You can't store data into a pointer.Pointers should point at memory location.
So to use a pointer in the right way ,it must always point at a valid memory location in stack or memory dynamically allocated in heap.
this char * names[3] is an array of pointers ,so you need to reserve memory for it and then initialize it.You need to use some thing like this:
char *name[3];
for(int i=0;i<3;i++)
{
name[i]=malloc(strlen(string)+1);
}
also you should allocate memory for char *arr too.
char *arr=malloc(strlen(data)+1)
then initialized it.

Why isn't scanf working when I try entering strings in a char pointer array?

#include<stdio.h>
int main(){
char *msg[10];
scanf("%s", msg[0]);
scanf("%s", msg[1]);
scanf("%s", msg[2]);
scanf("%s", msg[3]);
}
When I try to run this code, it gives errors. Am I doing something wrong? I'm still a beginner in C language.
char *msg[10];
Here msg is array of 10 char pointer and they are not initialized. If you want to store something into them, first allocate the memory dynamically.
for(int i = 0; i < 10; i++) {
msg[i] = malloc(MAX_NO_OF_BYTES); /* MAX_NO_OF_BYTES is the no of bytes you want to allocate */
scanf("%s",msg[i]); /* store the data into dynamically allocated memory */
}
print it & do the operation as you wanted
for(int i = 0; i < 10; i++) {
printf("%s\n",msg[i]);
/** operation with array of char pointer **/
}
Once work is done, free the dynamically allocated memory using free() for each char pointer as
for(int i = 0; i < 10; i++) {
free(msg[i]);
}
I hope it helps.
The trouble is that char *msg[10] is a array of 10 char pointers for which you need to explicitly allocate memory or use a static array instead.
Option-1:
for (i=0; i<10; i++)
{
msg[i] = malloc(sizeof(char) * 100)
}
Option-2
char msg[10][100]

how to manually concat a char **args to char *args

so I'm trying to write a function that concats a char**args to a char*args
What I have so far is":
char *concat(char **array)
{
int size = 0;
int i=0;
int j=0;
int z=0;
while (array[i]!=NULL)
{
printf(" %s \n", array[i]);
size = size + sizeof(array[i])-sizeof(char); //get the total size, minus the
//size of the null pointer
printf("%d \n",size);
i++;
}
size = size+1; //add 1 to include 1 null termination at the end
char *newCommand = (char*) malloc(size);
i=0;
while(i<sizeof(newCommand))
{
j=0;
z=0;
while (array[j][z]!='\0')
{
newCommand[i] = array[j][z];
i++;
z++;
}
j++;
}
newCommand[sizeof(newCommand)-1]='\0';
return newCommand;
}
this doesn't seem to work. Anyone know what's wrong?
I'd do it like this (untested):
int size = 0;
int count = 0;
while (array[count]) {
size += strlen(array[i]);
count++;
}
char *newCommand = malloc(size + 1);
char *p = newCommand;
newCommand[0] = 0; // Null-terminate for the case where count == 0
for (int i = 0; i < count; i++) {
strcpy(p, array[i]);
p += strlen(array[i]);
}
First, your size calculation was wrong. You wanted the size of the strings, but sizeof(array[i]) gives you the size of a single element in your array which is a pointer and thus 4 (32-bit) or 8 (64-bit). You need to use strlen instead.
Next, your manual copying was also off. It's easier to do it with a moving pointer and strcpy (which is to be avoided normally but we've calculated the sizes with strlen already so it's OK here). The use of strcpy here also takes care of null termination.
Main issue is that you keep using sizeof() with a pointer argument, whereas I think you are trying to get the size of the corresponding array.
sizeof() can only give you information that's available at compile time, such as the sizes of raw types like char and int, and the sizes of arrays with a fixed length such as a char[10]. The sizes of the strings pointed to by a char* is only computable at run time, because it depends on the exact values passed to your function.
For sizeof(newCommand) you probably need size, and for sizeof(array[i]), you probably need strlen(array[i]).

Resources