copy a struct array to another (not struct) array in C - c

I am trying to copy name array to another array and print it
#include <stdio.h>
typedef struct
{
char name[100];
int age;
} data;
int main() {
char new_array[100];
data people[] = {{ "john", 12},{" kate", 15}};
for(int i =0; i < sizeof(people); i++) {
new_array[i] = people[i].name;
printf("%c ", new_array[i]);
}
return 0;
}
But it gives me an error:
error: assignment to ‘char’ from ‘char *’ makes integer from pointer without a cast [-Werror=int-conversion]
new_array[i] = people[i].name;
^
How do I fix this?

You can change:
char new_array[100];
to:
char new_array[10][100]; // for maximum 10 strings
Then using strcpy to copy string in c. If you want to calculate the number of elements of array, using:
sizeof(people)/sizeof(people[0]);
Then, the for loop becomes:
for(int i =0; i < sizeof(people)/sizeof(people[0]); i++) {
strcpy(new_array[i],people[i].name);
printf("%s ", new_array[i]);
}

You are trying to assign a string to a char which is described by your error. To copy a string to a char array, you should use strcpy().
Also, your new_array is a mere array of characters and has no way to differentiate two different names.
To make it an array of strings, you should use a 2D array where you can index the row to get different strings like below
char new_array[10][100]
This makes an array of 10 strings of 100 characters each.
Also, your iteration over the array of structure is messy.
To get correct size of array of structure, you should use
int size = sizeof(people)/sizeof(people[0])
So, your final code becomes-
#include <stdio.h>
#include <string.h>
typedef struct
{
char name[100];
int age;
} data;
int main() {
char new_array[10][100];
data people[] = {{ "john", 12},{" kate", 15}};
for(int i =0; i < sizeof(people)/sizeof(people[0]); i++) {
strcpy(new_array[i],people[i].name);
printf("%s ", new_array[i]);
}
return 0;
}

Related

GCC Compilation Error on array assignment

I am trying to convert a string into its equivalent matrix form in C. The matrix would have 3 rows and as many columns as required. The following code doesn't compile, and I haven't figured out what's going wrong.
The error that GCC throws is:
app.c:10:25: error: subscripted value is not an array, pointer, or vector
printf("%d\n", arr[i][k]);
~~~^~
1 error generated.
Main file (app.c):
#include <stdio.h>
#include "converter.h"
int main() {
char source[] = "This is the source. "; // placeholder text
int arr = convert(source);
for (int i = 0; i < 21; i++) {
for (int k = 0; k < 3; k++) {
printf("%d\n", arr[i][k]); // error occurs at this line.
}
}
return 0;
}
converter.c file:
// Converts an input string to its respective ASCII matrix.
#include <string.h>
#include <stdio.h>
#include "converter.h"
// Converts the entire string into an multi-dimensional array.
int convert(char text[]){
// copy the input text into a local store.
char store[strlen(text)];
strcpy(store, text);
// make sure the length of the input string is a multiple of 3 or make it so.
int excess = strlen(store)%3;
char excess_spaces[3] = " ";
if (excess != 0) {
strncat(store, excess_spaces, 3-excess);
}
// covert the source into an array
int arr[3][strlen(store)/3];
int steps = strlen(store)/3;
for (int i = 0; i < steps; i++) {
int t[3];
for (int k = 0; k < 3; k++) {
t[k] = (int) store[3*i+k];
arr[k][i] = t[k];
}
}
return arr;
}
converter.h file:
int convert(char text[]);
There are multiple issues in this code.
The allocating storage for string, one must include one byte for a null terminator. Replace:
char store[strlen(text)];
with:
char store[strlen(text) + 1];
Additionally store must be big enough to contain the excess which is up to 3 spaces.
char store[strlen(text) + 3 + 1];
In C you cannot use an array as a value. It is converted to a pointer to it's first element in pretty must every context. Therefore it is not possible to return an array directly. It could be workaround by wrapping an array with a struct but it a topic for another day.
As result return arr will be equivalent to return &arr[0] which is int (*)[XXX] a pointer to int array of size XXX.
Never ever return a pointer to an object with automatic storage. It's Undefined Behaviour. I know that the intention was returning an array not a pointer to it. Create an object with dynamic storage with malloc-like function to safely return a pointer.
Returning Variable Length Array (VLA) by value is not possible because Variably Modified (VM) types cannot be defined at file scope.
It looks that indices are swapped in:
printf("%d\n", arr[i][k]);
I guess it should be arr[k][i].
Now... let's solve it.
Returning VLA is tricky. One solution is to pass a pointer to VLA as an argument. See https://stackoverflow.com/a/14088851/4989451.
The issue with this solution is that the caller must be able to compute the dimensions.
The other way it to wrap the result of the convert() to a struct. Note that the function and the struct can share the name. The result with have the sizes of VLA as n and m members and the pointer to the data as arr. The caller need to cast it to proper VM type.
To cumbersome casts between the non-trivial pointer types, one can cast via void*.
When all work with the array is done, release it memory with free().
// Converts an input string to its respective ASCII matrix.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
// Converts the entire string into an multi-dimensional array.
struct convert {
int n, m;
int *arr;
} convert(char text[]){
// copy the input text into a local store.
size_t textlen = strlen(text);
char store[textlen + 3 + 1];
strcpy(store, text);
// make sure the length of the input string is a multiple of 3 or make it so.
int excess = textlen % 3;
char excess_spaces[3] = " ";
if (excess != 0) {
strncat(store, excess_spaces, 3-excess);
}
size_t storelen = strlen(store);
// allocate VLA with dynamic storage
int (*arr)[storelen / 3] = malloc(3 * sizeof *arr);
// covert the source into an array
int steps = storelen / 3;
for (int i = 0; i < steps; i++) {
int t[3];
for (int k = 0; k < 3; k++) {
t[k] = (int) store[3*i+k];
arr[k][i] = t[k];
}
}
return (struct convert){ .n = 3, .m = steps, .arr = (int*)arr };
}
int main() {
char source[] = "This is the source. "; // placeholder text
struct convert res = convert(source);
int n = res.n, m = res.m;
int (*arr)[m] = (void*)res.arr;
for (int i = 0; i < n; i++, puts("")) {
for (int k = 0; k < m; k++) {
printf("%d ", arr[i][k]); // error occurs at this line.
}
}
free(arr);
return 0;
}

Incrementing the pointer to string array returns NULL

I'm trying to pass an array of strings to a function to print to the screen. The first string prints fine. The proceeding strings, however, are null and thus don't print anything. If I get the pointer directly to the first string instead of the array I can increment it by the size of of the character array and everything prints correctly. If I try to increment the pointer to the array of strings that's where I get the null. Why does this happen and how can I correctly print the array. Also I'm using visual studio if that is affecting it any at all given the C standard it uses.
I don't think the error lies with the call because the pointer passed points to the string array address.
//How I'm passing the array
char headings[4][20] = { "Name", "Record Number", "Quantity", "Cost"};
int widths[4] = {20, 20, 20, 20 };
headers(&headings[0][0], &widths[0], 4);
//Function
void headers(char **heads, int *columnWidths, int noOfColumns) {
int headLength = 0;
printf("|");
for (int i = 0; i < noOfColumns; i++) {
headLength += printf("%*s|", *columnWidths, heads);
columnWidths++;
heads ++;
}
printf("\n");
for (int i = 0; i < headLength+1; i++) {
printf("-");
}
printf("\n");
}
This is the output that I get:
| Name| | | |
but I'm expecting this output:
| Name| Record Number| Quantity| Cost|
If you have a 2D Array heading, your headers function should also accept a 2D array. Although arrays generally decay to pointers when passed to functions, the type char** heads is not the same as char headings[4][20]. And your compiler should warn you about it also.
The following bit of code prints the correct output.
#include <stdio.h>
#include <string.h>
//Function
void headers(char heads[4][20], int *columnWidths, int noOfColumns) {
int headLength = 0;
printf("|");
for (int i = 0; i < noOfColumns; i++) {
headLength += printf("%*s|", *columnWidths, *heads);
columnWidths++;
heads ++;
}
printf("\n");
for (int i = 0; i < headLength+1; i++) {
printf("-");
}
printf("\n");
}
int main(){
char headings[4][20] = { "Name", "Record Number", "Quantity", "Cost"};
int widths[4] = {20, 20, 20, 20};
headers(headings, &widths[0], 4);
}
Note: you could also change the headers function to accept char heads[][20], but not char[][] as that would give you an obvious compiler error.
You would need to pass headings into your function, not the address of the first character of the first function. But in C multidimensional arrays are a complete distinct type and the memory layout differs significantly from array of char *.
This is a working variant, which supports arbitrary dimensions, unlike the accepted solution which only supports the array dimensions 4 string with 20 chars each:
#include <stdio.h>
#include <string.h>
//Function
void headers(const char **heads, int *columnWidths) {
int headLength = 0;
printf("|");
while (*heads) {
headLength += printf("%*s|", *columnWidths, *heads);
columnWidths++;
heads ++;
}
printf("\n");
for (int i = 0; i < headLength+1; i++) {
printf("-");
}
printf("\n");
}
int main(){
const char *headings[] = { "Name", "Record Number", "Quantity", "Cost", 0};
int widths[4] = {20, 20, 20, 20};
headers(headings, &widths[0]);
}
I don't think the error lies with the call because the pointer passed points to the string array address.
No. The pointer to the string array is called headings. This is an array of char, with two dimensions. It is not possible to iterate over the individual strings without knowledge of the layout of the array.
Instead it is usually better to define an array of char * and initialize this with the individual strings. You can see how the definition of the array content looks exactly the same as in the multidimensional array variant, but the memory layout is very different, and it is now possible to iterate over the strings like you initially intended.

How to concatenate two string array index by index in C?

I have two arrays of strings called name and subject. I want to have another array of strings whose elements are obtained by concatenating the string of the first array with the string with the same index of the other array. The new array should be the output of a function.
Here I give a code sample, but I am unable to compile due to getting errors.
I have also seen this question but I am unable to use it.
Can anyone give me a hint on how to solve this without dynamic allocation and also with dynamic allocation?
#include <stdio.h>
#include <string.h>
const int MAX = 4;
char* concancate_string(char* name,char* subject);
int main () {
char* name[] = {
"michel",
"sam",
"roy",
"romi"
};
char* subject[] = {
"physics",
"math",
"chemistry",
"biology"
};
char* p[];
p=concancate_string(name,subject);
for ( int i = 0; i < MAX; i++) {
printf("name and subject[%d] = %s\n", i, name[i] );
}
return 0;
}
char* concancate_string(char* name,char* subject)
{
for ( int i = 0; i < MAX; i++) {
strcat(name[i]," : ");
strcat(name[i],subject[i]);
}
return name;
}
resulted output array:
{
"michel : physics",
"sam : math",
"roy : chemistry",
"romi : biology"
}
Here's my attempt with dynamic allocation:
char **concancate_string(const char *name[], const char *subject[], size_t n) {
char **destin = malloc(n * sizeof *destin);
for (int i = 0; i < n; i++) {
destin[i] = malloc(strlen(name[i]) + strlen(subject[i]) + 3 + 1); // add space for " : " and terminating '\0'
sprintf(destin[i], "%s : %s", name[i], subject[i]);
}
return destin;
}
Remember to all free(destin[k]) and free(destin).
See code running on https://ideone.com/3Qb7v1
First of all, this declaration doesn't work:
char* p[]; // how much stack memory should the compiler reserve?
p=concancate_string(name,subject); // can't assign to an array
Instead, do this:
char **p = concancate_string(name, subject); // you can assign to pointers, though
Also this signature is wrong:
char* concancate_string(char* name,char* subject);
It's taking and returning arrays of char*, not single char*, so it should be:
char **concancate_string(char **name, char **subject);
Furthermore, you can't concatenate to a pointer that you assigned a string literal to. Those point to your program's binary, which is readonly. Instead, the function should look like this:
char **concancate_string(char **name, char **subject)
{
char **pointers = malloc(MAX * sizeof(char*));
for (int i = 0; i < MAX; i++) {
pointers[i] = malloc(strlen(name[i]) + strlen(subject[i]) + 4);
sprintf(pointers[i], "%s : %s", name[i], subject[i]);
}
return pointers;
}
Note how we're allocating an array for the pointers, then allocate memory for every single string, then use sprintf to assemble them (you could also use strcpy and strcat, of course).
Finally, your print is wrong. You make your p, but instead of printing that, you print name. It should instead be:
printf("name and subject[%d] = %s\n", i, p[i]);
And when you're done, the memory should be freed:
for (int i = 0; i < MAX; i++) {
free(p[i]);
}
free(p);
My suggestion to you is to write your programs one part of the time, only starting with the next part when the last part is tested and works well. If you just write the entire program without testing and then it doesn't work because there's errors all over the place, it becomes much harder to find them.
If you can assume a maximum length of each string then there is no need to use dynamic allocation. In the example below (which compiles and run) I assumed each string has a length of 100 (99 usable characters plus the \0 character).
So I defined an array using your MAX constant and 100 as char result[MAX][100] = {0};. {0} initializes all the elements to 0 (this initialization works only with 0. Then I passed this new array to the function. Note that you were defining the function parameter as char* name which means a string: you want to pass an array of strings: I redefined as concancate_string(char* name[], char* subject[], char out[MAX][100]): note the difference.
Strings are simply concatenated with strcat. There is also another function strncat which allows you to specify the max number of char to copy.
#include <stdio.h>
#include <string.h>
const int MAX = 4;
int concancate_string(char* name[], char* subject[], char out[MAX][100]);
int main () {
char result[MAX][100] = {0} ;
char* name[] = {
"michel",
"sam",
"roy",
"romi"
};
char* subject[] = {
"physics",
"math",
"chemistry",
"biology"
};
int p=concancate_string(name, subject, result);
for ( int i = 0; i < MAX; i++) {
printf("%s\n", result[i] );
}
return 0;
}
int concancate_string(char* name[], char* subject[], char out[MAX][100])
{
for ( int i = 0; i < MAX; i++) {
strcat(out[i], name[i]);
//printf("%s\n", out[i] );
strcat(out[i], " : ");
//printf("%s\n", out[i] );
strcat(out[i], subject[i]);
//printf("%s\n", out[i] );
}
retur

Printing array of struct Segmentation fault

I'm trying to print my struct. I want it to show:
id: BBB-188
brand: BMW
pic: 1 2 3.
Right now the result is this:
id: BBB-188
name: BMW
Segmentation fault: 11.
Does anyone know what is wrong with my code?
#define MAX 10000
#define IDSIZE 11
#define BRANDSIZE 50
#define PICSIZE 10
typedef struct{
char id[IDSIZE+1];
char brand[BRANDSIZE+1];
int *pic;
} Car;
void printCar(Car *pCar,int carcount, int imagecount) {
printf("id: %s \n",pCar->id);
printf("brand: %s \n",pCar->brand);
for(int i=0; i< imagecount; i++){
printf("pic: %d \n",pCar->pic[i]);
}
}
Car initCar(char itsId[],char itsBrand[],int itsPic, int imagecount){
Car newCar;
strcpy(newCar.id, itsId);
strcpy(newCar.brand, itsBrand);
for (int i = 0; i < imagecount; i++){
newCar.pic = itsPic;
}
return newCar;
}
int main(void){
int carcount=0;
int imagecount=0;
int test[3]={1,2,3};
Car myCar = initCar("BBB-188","BMW", test, 3 );
carcount=1;
imagecount=3;
printCar(&myCar,carcount,imagecount);
return 0;
}
The handling of pic is broken and very confusing.
You seem to want to represent it as an array of integers, but you don't store the length. Thus it has to be always three, but then you can just use an array in the structure, i.e.:
int pic[3];
instead of
int *pic;
Also the assignment inside initCar() makes no sense, you're looping but simply assigning the same integer value (!) to the pointer imagecount times, no data is being copied.
If you want the length of the picture array to really be variable, you must store the length and allocate memory for holding the numbers. So in initCar() you must have:
newCar.pic = malloc(imagecount * sizeof *newCar.pic);
memcpy(newCar.pic, itsPic, imagecount * sizeof *newCar.pic);
but then itsPic must of course be of type const int *.
You need to pass itsPic as a pointer in initCar. If you're doing so, you don't need the for loop for the affectation.
Car initCar(char itsId[],char itsBrand[],int* itsPic, int imagecount){
Car newCar;
strcpy(newCar.id, itsId);
strcpy(newCar.brand, itsBrand);
//for (int i = 0; i < imagecount; i++){
newCar.pic = itsPic;
//}
return newCar;
}

Develop a user-defined function to sort the array in a non-decreasing order

I just learned about pointer and tried the program on the textbook,
"Declare an array of char type with size 8, ask the user to input a
string and then assign to the array. Develop a user-defined
function to sort the array in a non-decreasing order. Print the array
before and after sorting in the main function. The function
prototype is given as
void arr_sort( char * cPtr)"
I don't know very clear what mistake I have made.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void print(char *a[]);
void arr_sort( char *a[]);
int main()
{
int i;
char *array[8];
printf("Please input a string with size 7:");
for(i=0;i<7;i++)
{
scanf("%s",array);
}
printf("the array before sorting is");
print(array);
arr_sort(array);
print(array);
return 0;
}
void arr_sort( char *a[])
{
int i,j;
char *temp;
for(i=0;i<7;i++)
{
for(j=0;j<7;j++)
{
if(strcmp(a[j],a[j+1])>0)
{
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}
}
void print(char *a[])
{
int i;
for(i=0;i<7;i++)
{
printf("%s ",a[i]);
}
}
doing a quick 'google' for a bubble sort, in C, results in:
// where 'n' is the number of entries in the array
// where 'array' is declared as 'int array[n];
for ( int c = 0 ; c < ( n - 1 ); c++ )
{
for ( int d = 0 ; d < n - c - 1; d++ )
{
if ( array[d] > array[d+1] ) /* For decreasing order use < */
{
int temp = array[d];
array[d] = array[d+1];
array[d+1] = temp;
}
}
}
Notice the limits on the upper bound of the index variables.
in your program you will be using char rather than int for temp and for the declaration of array[]
notice there is no need for anything in the string.h header file.
notice the limiting of the scope of the local variables c, d, and temp
The comments on your posted question cover the problems in the posted code, so I will not repeat all of them here.
for(i=0;i<7;i++) {
scanf("%s",array);
}
If you want 8 strings of length 7, you can't scanf them into the array. Your array is an array of pointers as defined here:
char *array[8];
Which is very different from this:
char array[8];
The first is an array that stores 8 pointers to strings. The second is an array that stores 8 characters. If you wanted to store a single string, you would do this:
char array[8];
printf("Please input a string with size 7: ");
scanf("%s", array);
Which is probably what you're used to at this point.
So, an array of pointers is just like a list of little arrows that point to blocks of memory. Your array doesn't store any characters itself, which is why you can't scanf directly into it.
int main(void) {
char *arr[8];
char new_word[8];
for(int i = 0; i < 8; i++) {
printf("Enter a new word of length 7: ");
scanf("%s", new_word);
arr[i] = malloc(strlen(new_word) + 1);
strcpy(arr[i], new_word);
}
for(int i = 0; i < 8; i++) {
printf("%s\n", arr[i]);
}
return 0;
}
This program creates two arrays: a pointer array (arr) and a character array (new_word). In the loop, you ask for seven strings of length 7, which is scanf'd into the character array. New memory is set aside for that string with malloc. Then, the string is copied into the block of memory that your first array pointer points to. We increment our array index with the for loop so that now we're using the next pointer, and so on.
It's important to use strcpy and copy the string out of the character array every time, otherwise at the end, you will just have an array of pointers pointing to a single string, new_word.

Resources