Creating a 1-D array of strings from user input in C - arrays

I was attempting to create an array from user input in C. My code was as follows
#include <stdio.h>
#include <stdlib.h>
char** create_array(int num);
int main(){
char** my_array;
int i;
printf("%s", "Input the size of the array: ");
scanf("%d", &i);
my_array = create_array(i);
for (int m = 0; m < i; m++){
printf("%s\n", (char*)my_array[m]);
}
}
char ** create_array(int num){
char** array = malloc(num * sizeof(char*));
for (int i = 0; i < num; i++) {
char temp[32];
printf("Input element %d of the array: ", i);
scanf("%s", temp);
array[i] = temp;
}
for (int m = 0; m < num; m++){
printf("%s\n", array[m]);
}
printf("end of func\n");
return array;
}
I was having (possibly unrelated?) issues with segmentation faults until I replaced the declaration of temp from char *temp; to char temp[32];. I am not sure of why declaring temp as a char pointer creates the segmentation fault, if that is a simple related answer let me know, if not I will ask in another question.
However, when I run this code, upon inputting
Input the size of the array: 2
Input element 0 of the array: value0
Input element 1 of the array: value1
I get
value1
value1
end of func
Segmentation fault (core dumped)
So to me it seems like temp somehow isn't changing when the for loop executes next iteration. I'm not sure why or how that would ever happen though. I also tried changing
printf("%s\n", my_array[m]);
to
printf("%s\n", (char*)my_array[m]);
but that didn't seem to help either.
Any ideas?
Thanks

I believe this is what you're looking for. The trick is allocate the memory for the strings on the heap. Saving pointers to char temp[32]; is dangerous because it's in automatic storage. As #Spikatrix said in a comment, that memory is not guaranteed to be in a valid state between each iteration of the loop. With the data on the heap, there's a well-defined region of memory set aside and identified by the pointer returned from malloc.
There's also a lot of good reason to not use scanf. As is, your code does not do any bounds checks and can easily overwrite the 32-byte array allocated for each string.
#include <stdio.h>
#include <stdlib.h>
char** create_array(int num);
int main(){
int num_strings;
printf("Input the size of the array: ");
scanf("%d", &num_strings);
printf("\n");
char** my_array = create_array(num_strings);
for (int i = 0; i < num_strings; i++){
printf("%s\n", my_array[i]);
}
for (int i = 0; i < num_strings; i++) {
free(my_array[i]);
}
free(my_array);
}
char** create_array(int num) {
char** array = malloc(num * sizeof(char*));
for (int i = 0; i < num; i++) {
array[i] = malloc(32);
printf("Input element %d of the array: ", i);
scanf("%s", array[i]);
printf("\n");
}
printf("end of func\n");
return array;
}

Related

Cannot assign values to array of pointers in C

I want to copy my array over to a pointer, so I can sort the array without changing the original. I'm not getting any errors, and am at a dead end. I've tried printing the pointer's contents, but it's always junk data. If anyone could help me it'd be much appreciated.
#include <stdio.h>
void bubbleSort(char *array[], int arrIndex);
void displaySort (char *array[], int arrIndex);
int main (void)
{
int index;
int count = 0;
printf("Enter number of people (0 - 50): ");
scanf("%d", &index);
index -= 1;
char userLastFirst[25][index];
int userAge[index];
//defining pointer
char *namePtr[25][index];
//do while loop, loops while count is less than or equal to the index
do{
printf("Enter name %d (last, first): ", count);
scanf(" %[^\n]s", userLastFirst[count]);
printf("Enter age %d: ", count);
scanf("%d", &userAge[count]);
// printf("\n\n%s %d\n\n", userLastFirst[count], userAge[count]);
count++;
} while (count <= index);
//assigning values to pointer
for(int i = 0; i < index; i++){
namePtr[25][i] = &userLastFirst[25][i];
}
//does not print values of pointer
for(int i = 0; i < index; i++){
printf("value of ptr[%d] = %s\n", i, namePtr[i]);
}
bubbleSort(*namePtr, index);
displaySort(*namePtr, index);
return 0;
}
void bubbleSort(char *array[], int arrIndex)
{
for (unsigned int pass = 0; pass < arrIndex - 1; ++pass) {
for (int i = 0; i < arrIndex - 1; ++i) {
if (array[i] < array[i + 1]) {
int temp = *array[i];
*array[i] = *array[i + 1];
*array[i + 1] = temp;
}
}
}
}
void displaySort(char *array[], int arrIndex)
{
for(int i = 0; i < arrIndex; i++){
printf("%s",*array[i]);
}
}
Sorry it's a lot, but I've looked everywhere, and am not exactly sure what the problem is. I suspect it's how I pass pointers thru the functions, or how I'm using * and & but am not totally sure what I'm doing wrong. The for loop below the one that assigns the array values to the pointer is for testing. It's supposed to print out the values I had given it in the previous for loop, but it doesn't. It just prints junk data.
There are couple of issues here, and since I don't know what exactly you want your final code to look like, I am going to give a few examples of what is wrong and how you could possibly fix that.
char userLastFirst[25][index];
This should be
char userLastFirst[index][25];
You don't want 25 people with names up to index characters in them, but rather index people with names up to 25 characters int them.
char *namePtr[25][index];
should be
char namePtr[index][25];
Same as before + you don't need the * here. Since you decided to go with vla let's stick with it. You would use * and more specifically char ** if you went with malloc/calloc.
namePtr[25][i] = &userLastFirst[25][i];
rather than doing this awkward copying, try:
strcpy(namePtr[i], userLastFirst[i]);
it copies the entire string for you, rather than just a single character. You will need to #include the <string.h> library for that.
void bubbleSort(char *array[], int arrIndex)
The first bubble sort argument should be:
char array[][25] // the same in displaySort
if you want to do it without the hassle of malloc/calloc.
And also don't go with int as your temp type. Rather do char temp[25] and copy them around with strcpy.
And don't compare strings with <, it doesn't work in C. Use strcmp for that.
And that's it for doing it without malloc/calloc, here's an example code:
#include <stdio.h>
#include <string.h>
void bubbleSort(char array[][25], int size);
void displaySort(char array[][25], int size);
int main (void)
{
int num_of_people;
printf("Enter number of people (0 - 50): ");
scanf("%d", &num_of_people);
char original_array[num_of_people][25];
char copied_array[num_of_people][25];
for (int i = 0; i < num_of_people; i++) {
printf("Enter name %d (last, first): ", i);
scanf(" %[^\n]s", original_array[i]);
}
for(int i = 0; i < num_of_people; i++){
strcpy(copied_array[i], original_array[i]);
}
bubbleSort(copied_array, num_of_people);
displaySort(copied_array, num_of_people);
return 0;
}
void bubbleSort(char array[][25], int size)
{
for (int i = 0; i < size - 1; ++i) {
for (int j = 0; j < size - 1 - i; ++j) {
if (strcmp(array[j], array[j + 1]) > 0) {
char temp[25];
strcpy(temp, array[j]);
strcpy(array[j], array[j + 1]);
strcpy(array[j + 1], temp);
}
}
}
}
void displaySort(char array[][25], int size)
{
for(int i = 0; i < size; i++){
printf("%s\n",array[i]);
}
}
and the program work like this:
Enter number of people (0 - 50): 4
Enter name 0 (last, first): Kowalski, Jan
Enter name 1 (last, first): Kowalska, Anna
Enter name 2 (last, first): Nowak, Miłosz
Enter name 3 (last, first): Amper, Ohm
Amper, Ohm
Kowalska, Anna
Kowalski, Jan
Nowak, Miłosz
I hope this is something you wanted to achieve.

The number of elements in a pointer as an array

I'm trying to count the number of elements in an array as a pointer as the code followed:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *ptr = (int *) malloc(sizeof(int*));
for(int i=0; i<8; i++)
{
printf("The number: " );
scanf("%d", &ptr[i]);
}
int size = sizeof(ptr)/sizeof(int);
printf("%d\n", size);
return 0;
}
I have tried the syntax for an array size = sizeof(ptr)/sizeof(int);but I got the wrong answer which is 1 for all cases. I don't know how to get the correct answer, which is 8 for this case
Unfortunately, you cannot get the size of an array allocated with malloc (because you are actually getting the size of a pointer). You must always store that somwhere else. Since you always allocate 8 elements, why not make it a static array?
#include <stdio.h>
int main()
{
int arr[8];
for(int i=0; i<8; i++)
{
printf("The number: " );
scanf("%d", &arr[i]);
}
int size = sizeof(arr)/sizeof(int);
printf("%d\n", size);
return 0;
}

Array with random numbers only contains the same values?

I wrote a program which should create many random numbers and save it in an array. I also checked up many questions and everyone just saying to set seed one time but that does not solve my problem.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
void printArray(int *arr){
for(int i = 0; arr[i] != '\0'; i++){
printf("%i, ", *arr);
}
}
int main(int argc, char* argv[])
{
// set seed
srand(time(NULL));
int number_max;
// first argument
int arg1 = atoi(argv[1]);
if(arg1 <= 4){
printf("number to small or not a number\n");
return 0;
}
// 2^n space for random numbers
number_max = pow(2, arg1);
// initialize array
int numbers[number_max];
// create 2^n random numbers from 0 to 10000
for(int i = 0; i < number_max; i++){
numbers[i] = (rand() % (10000 - 0 + 1)) + 0;
}
// print Array
printArray(numbers);
}
That is my code. My whole array contains the same value. I understand the problem, but don't know how to solve.
Thanks for your help :)
Few things:
Your loop condition for (int i = 0; arr[i] != '\0'; i++) requires that the array is terminated with zero. This is not the case unless you explicitly terminate the array with zero. Also, if any of the values in numbers is zero, it will stop there.
You are always dereferencing the first element in the array. Print arr[i] or *(arr + i) to print the actual array values one by one.
Not code related, but it's grammatically correct to say "number too small", not "number to small". :-)
You see same values because you are printing same element *arr, which is equivalent to arr[0].
Maybe you want this:
void printArray(int *arr){
for(; *arr != '\0'; arr++){
printf("%i, ", *arr);
}
}
or this:
void printArray(int *arr){
for(int i = 0; arr[i] != '\0'; i++){
printf("%i, ", *(arr + i));
}
}
or this:
void printArray(int *arr){
for(int i = 0; arr[i] != '\0'; i++){
printf("%i, ", arr[i]);
}
}
Note that you can write simply 0 instead of '\0'.

free() the reserved data with malloc

Hi I have written this Program which create a list of books which is given by the User and i can't free the my_value at the end of program and get a lot of errors . This is my Code
#include <stdio.h>
#include <stdlib.h>
int main(){
int n;
printf("Please Enter the Number of Books:\n");
scanf("%d",&n);
char **array=(char *) malloc((n+1)*sizeof(char *));
for(int i=0;i<n;i++){
array[i] = (char *)malloc(sizeof(char *));
}
for(int i=0;i<n;i++){
char *my_value=(char *) malloc(sizeof(char)*100);
printf("Please Enter the Name of the %dth Book:\n",i+1);
scanf("%s",my_value);
*(array+i)=my_value;
free(my_value);
}
for(int i=0;i<n;i++){
printf("\n The Book Nr.%d is %s \n",i+1,*(array+i));
}
for(int i=0;i<n;i++){
free(array[i]);
}
free(array);
return 0 ;
}
First, in
char **array=(char *) malloc((n+1)*sizeof(char *));
you don't need n+1 pointers since you use only n.
Then, this loop
for(int i=0;i<n;i++){
array[i] = (char *)malloc(sizeof(char *));
}
is unnecessary (and wrong). array[i] is to be overwritten just after.
In the next loop
*(array+i)=my_value; // is array[i] = my_value
free(my_value); // <=== why? remove that line!
you free what you just allocated -- array[i] cannot be used anymore from that point! Lead to undefined behavior.

Call a function that receives an array using a pointer

So I've this:
int main()
{
int workers;
printf("How many workers are there?\n");
scanf("%d", &workers);
printf("What are their preferences?\n");
int *pref = malloc(workers * sizeof(int));
if (pref == NULL)
return -1;
fillPreferences(pref, workers);
return 0;
}
I want now to fill the "pref" 2d array in this function:
void fillPreferences(int pref[][], int size)
{
for (int i=0;i<size;i++)
{
for (int j=0;j<size;j++)
{
scanf(" %d", &pref[i][j]);
}
}
}
It doesn't work, probably because I'm using the pointer wrong. How can I use malloc and then call a function and receive the values in the 2d array by doing pref[i][j]? (Note that I'm not looking to do something like scanf(..., &pref+i) or whatever. I need to actually use that 2d array.
Thanks :)
When you write a[i], it is turned into *(a+i). That is, a[i] accesses the memory by a+i address (well, it is a+i*sizeof(element) even).
As such, a[i][j] means *(*(a+i)+j). Two memory accesses. For this to work, your a should be an array of arrays. That is, you need to malloc its elements first and then malloc a memory to hold them.
In your particular case, i doubt you need it. What you need is make it 1D-array (which is it already) and calculate index from your two indices in whatever fashion you wish.
Your pref array is 1D so you can make it in this way:
#include <stdio.h>
#include <stdlib.h>
void fillPreferences(int **pref, int size)
{
int prefNum=0;
for (int i=0;i<size;i++)
{
puts("Number of preferences");
scanf("%d",&prefNum);
pref[i]=malloc(sizeof(int)*prefNum);
puts("Enter preferences");
for(int j=0;j<prefNum;j++){
scanf(" %d", &pref[i][j]);
}
}
}
int main()
{
int workers;
printf("How many workers are there?\n");
scanf("%d", &workers);
printf("What are their preferences?\n");
int **pref = malloc(workers * sizeof(int *));
if (pref == NULL)
return -1;
fillPreferences(pref, workers);
// Show values
printf("%d %d %d",pref[0][0],pref[1][0],pref[2][0]);
return 0;
}
You allocate memory for a 1D array, but the function you have is designed to accept a 2D array and fill it (although the function definition is incorrect and won't compile).
Corrected code:
#include <stdio.h>
#include <stdlib.h>
void fillPreferences(int** pref, int size)
{
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
scanf("%d", &pref[i][j]);
}
}
}
int main()
{
int workers;
printf("How many workers are there?\n");
scanf("%d", &workers);
printf("What are their preferences?\n");
int **pref = malloc(workers * sizeof(int*));
if (pref == NULL)
return -1;
for(int i = 0; i < workers; i++)
{
pref[i] = malloc(workers * sizeof(int));
if(pref[i] == NULL)
{
for(int j = 0; j < i; j++)
free(pref[j]);
free(pref);
return -1;
}
fillPreferences(pref, workers);
/* Don't forget to `free` everything after its use! */
return 0;
}

Resources