I'm trying to create a function for adding 1 element to each of the three pointer arrays (firstArray, lastArray, scoreArray). For this particular assignment, I'm supposed to use pointers and dynamic memory but no structures.
As the program is now, it automatically moves to adding an additional record and waits for all 3 parts of the user input. However, when the program calls the printRecords() function after running the addRecords() function, I get a segmentation fault. I assume this means I'm not passing the changes made in the addRecords() function back to the main therefore, there is nothing stored where the printRecords() function is trying to read. I've tried several times but have gotten nowhere.
How should I alter the 3 problem lines in addRecords() to pass the changes made to the arrays back to the main?
void printRecords(char **firstArray, char **lastArray, float **scoreArray, int n);
void addRecords(char **firstArray, char **lastArray, float **scoreArray, int *j);
int main(int argc, char** argv) {
int i = 0, n = 0;
printf("Please indicate the number of student records to be entered:");
scanf("%d",&n);
char **firstArray;
char **lastArray;
float **scoreArray;
firstArray = (char **)malloc(n*sizeof(char *));
lastArray = (char **)malloc(n*sizeof(char *));
scoreArray = (float **)malloc(n*sizeof(float *));
for(i=0;i<n;i++)
{
printf("Enter Record %d:",i+1);
firstArray[i] = (char *)malloc(n*sizeof(char));
lastArray[i] = (char *)malloc(n*sizeof(char));
scoreArray[i] = (float *)malloc(n*sizeof(float));
scanf("%s",firstArray[i]);
scanf("%s",lastArray[i]);
scanf("%f",scoreArray[i]);
}
addRecords(firstArray,lastArray,scoreArray,&n);
printRecords(firstArray,lastArray,scoreArray,n);
return (EXIT_SUCCESS);
}
void printRecords(char **firstArray, char **lastArray, float **scoreArray, int n)
{
int i = 0;
printf("\nPrinting %d student records....\n",n);
for(i=0;i<n;i++)
{
printf("Record %d: %s - %s - %.2f\n",i+1,firstArray[i],lastArray[i],*scoreArray[i]);
}
}
void addRecords(char **firstArray, char **lastArray, float **scoreArray, int *j)
{
int t = *j; //Assigning current number of records to temp variable
t++; //Increment by 1
*j = t; //Passes the new number of records back to main
printf("Enter Record %d:",t);
firstArray[t] = (char *)malloc(t*sizeof(char));
lastArray[t] = (char *)malloc(t*sizeof(char));
scoreArray[t] = (float *)malloc(t*sizeof(float));
scanf("%s",firstArray[t]); **//PROBLEM LINES**
scanf("%s",lastArray[t]); **//PROBLEM LINES**
scanf("%f",scoreArray[t]); **//PROBLEM LINES**
printf("\nNew record added successfully");
return;
}
I think your memory allocation for the strings is very confused. You have two layers - the arrays of pointers and the actual strings they point to. You are allocating the arrays once at size n. Oddly, the strings are also allocated at size n?? Those should probably be based on some parameter of the problem. In addRecords, you then allocate the added strings at a variable size based on the current number of records but you don't actually extend the arrays of pointers.
Finally, make sure you enforce any length limitations on the strings when you read in the records so you don't trash memory.
Related
I've included the code below if anyone would be kind enough to complile it to really see the problem. I'm trying to make a dynamically allocated shopping list to get my used to pointers and memory allocation.
The entries is stored in a 1D char array (seperated by null pointers). Arrays containing the location of the first character and entry length have also been created in order to navigate the list.
The code works for small entries, but when I use a list of large entries (e.g. 'adsjasdkasjdaksdj') suddenly my code thinks the length (strlen(message)) is something like '110040'. To me this looks like a memory error but I'm no computer scientist (more of an amateur coder). I tried extending the memory allocated using realloc() but the problem persists.. Any help would be greatly appreciated!
I've put the code in a loop to take 10 entries for testing purposes.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int listEntries = 0;
int main(int argc, const char * argv[]) {
//Initial definition and allocation of memory.
char *list;
list = (char *)malloc(sizeof(char)); //allocates the requested memory and returns a pointer to it.
int *entryLength; //Array to hold length of each entry.
entryLength = (int *)malloc(sizeof(int)); //allocates the requested memory and returns a pointer to it.
int *entryStart; //Array to hold start point of each entry.
entryStart = (int *)malloc(sizeof(int)); //allocates the requested memory and returns a pointer to it.
char *message; //Array to hold the user input.
message = (char *)malloc(sizeof(char)); //allocates the requested memory and returns a pointer to it.
int arraySize = 0; //Variable to hold the size of the array.
char input[32]; //Char array to take user input (copied to 'message' later)
for(int i=0;i<10;i++){
//Obtain user entry.
printf("Insert entry: \n");
scanf("%s",input);
//Transfer string pointer contents to usable char array of known size.
message = (char *)realloc(message, strlen(input)*sizeof(char));
int i=0;
while(input[i] != '\0'){
message[i] = input[i];
i++;
}
message[i]='\0';
//Add entry to list.
listEntries++;
//Find the current size of list.
arraySize=0;
for(i=0;i<listEntries;i++) {
arraySize+=entryLength[i];
printf("entryLength[%d] = %d\n",i,entryLength[i]);
}
//Reallocate memory to accomodate new data.
list = (char *)realloc(list, (arraySize+1)*sizeof(char)+2);
entryLength = (int *)realloc(entryLength,(listEntries*4)*sizeof(int)+2); //Over allocating
entryStart = (int *)realloc(entryStart,(listEntries*4)*sizeof(int)+2); //For safety in dev.
//Add new entry to data.
entryLength[listEntries-1]=(int)strlen(message);
printf("entryLength[%d] is: %d",listEntries-1,entryLength[listEntries-1]);
entryStart[listEntries-1]=arraySize;
//printf("Start point is: %d",entryStart[listEntries-1]);
for(i = 0; i < strlen(message); i++){
list[i+arraySize] = message[i];
}
//Print the new entry
for(int i = 0; i < arraySize; i++){
printf("%c",list[i]);
}
printf("\n");
}
}
I am given a text file of unknown size and i have to read it till the end, calculate the number of words, letters and some other stuff. To do this i try to read the entire file and save all the words in an array. I am told to use dynamic memory allocation since i don't know the size of the text file beforehand.
Before i get into the algorithm for calculating the words and letters i am trying to make the dynamic memory allocation work. This is my code:
int main(int argc, char *argv[]) {
FILE *fp; // file pointer
//defining a dynamic string array
char **array = malloc(10 * sizeof(char *)); //10 rows for now, will be dynamically changed later
int i,size = 10, current = 0; // current points to the position of the next slot to be filled
for(i=0; i<10; i++){
array[i] = malloc(20); //the max word size will be 20 characters (char size = 1 byte)
}
fillArray(fp, array, current, size);
return 0;
}
I define an array of strings, a variable showing its size, and a variable pointing to the slot where the next element will be added.
The functions are as follows:
int fillArray(FILE *fp, char **p, int ptr, int size){
puts("What's the name of the file (and format) to be accessed?\n (It has to be in the same directory as the program)");
char str[20];
gets(str); //getting the answer
fp = fopen((const char *)str, "r"); //opening file
int x=0, i=0, j;
while(x!=EOF){ // looping till we reach the end of the file
printf("current size: %d , next slot: %d\n", size, ptr);
if(ptr>=size){
printf("increasing size\n");
addSpace(p, &size);
}
x = fscanf(fp, "%19s", p[i]);
puts(p[i]);
i++;
ptr++;
}
}
void addSpace(char **p, int *size){ //remember to pass &size
//each time this is called, 10 more rows are added to the array
p = realloc(p,*size + 10);
int i;
for(i=*size; i<(*size)+10; i++){
p[i] = malloc(20);
}
*size += 10;
}
void freeSpace(char **p, int ptr){
//each time this is called, the rows are reduced so that they exactly fit the content
p = realloc(p, ptr); //remember that ptr points to the position of the last occupied slot + 1
}
At the beginning, the rows of the array are 10. Each time the words of the text don't fit the array, the function addSpace is called adding 10 more rows. The program runs succesfully 3 times (reaching 30 rows) and then crashes.
After using printf's to find out where the program crashes (because i am not used to the debugger yet), it seems that it crashes while trying to add 10 more rows (to 40). I can't figure out the problem or how to fix it. Any help is appreciated.
C is pass by value. The pointer p is passed to addSpace(p, &size);, and a copy of that pointer is created in the function. Once the copy is changed: p = realloc(p,*size + 10); the original stays the same.
After the realloc call, the original pointer is not valid anymore. Using it causes undefined behavior, a crash in your case.
Return the new value and assign it to the original pointer:
p = addSpace( p , &size );
Classic!
You are also passing in a double pointer which is reallocd, the address has changed between the caller and callee.
Also there's a realloc issue.
p = realloc(p,*size + 10);
If realloc fails, the original pointer to block of memory is clobbered.
The proper way to do this:
char **tmp_ptr = realloc(p, *size + 10);
if (tmp_ptr == NULL){
perror("Out of memory");
}else{
p = tmp_ptr;
}
return p;
You can do it another way, either return back the address of the new block or use triple pointers.
void addSpace(char ***p, int *size){ //remember to pass &size
//each time this is called, 10 more rows are added to the array
char **tmp_ptr = realloc(*p, *size + 10);
if (tmp_ptr == NULL){
perror("Out of memory");
}else{
*p = tmp_ptr;
}
int i;
for(i=*size; i<(*size)+10; i++){
*p[i] = malloc(20);
}
*size += 10;
}
And from the caller
addSpace(&p, &size);
I have a structure in c and I want to allocate memory for an array of my structure,
for this I'd created a function.
The problem is that only first element of array is working.
If I do allocation in main, it is working.
Here is my code:
typedef struct {
int id;
char* name;
}Car;
void read(Car**cars){
int n,i;
char name[50];
printf("Cars:"); scanf("%i",&n);
*cars = (Car*) malloc(n * sizeof(Car));
for(i=0;i<n;i++) {
printf("\nCar Name[%i]: ",i); scanf("%s",name);
(*cars[i]).id = i; //when i>0 then It crash here...
(*cars[i]).name = (char*) malloc(strlen(name)+1);
strcpy((*cars[i]).name, name);
printf("Cars Name -> %s ", (*cars[i]).name);
}
}
int main() {
Car *cars = NULL;
read(&cars);
return 0;
}
what I am doing wrong?
(*cars)[i].id = i; //when i>0 then It crash here...
This should work for you.
explanation:
you allocate n elements to the value of the pointer to the cars pointer.
but you try to derefference the value of the ith pointer to a cars element.
With my correction you derefference the firsts pointer's ith cars id. what is bad coded but should do what you want.
But what you probabbly want to do is asigning multiple pointers which at all point to a single car pointer instead ;)
than your crashing line could stay at it is.
I'm doing some practice on functions, pointers and arrays, and I'm having difficulty getting this program to run and compile. Basically I'm trying to declare an array, and then use a function to store values from the input array into a pointer char array, and then output the pointer array, but I can't seem to get it to work.
Here is the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void cut_alphabet(char a[]);
char convert(char b[]);
int main()
{
char array[10][1000];
int i;
for(i=0; i<10; i++)
{
printf(" Please input a string value");
fgets( array[i], 1000, stdin);
}
convert(array[10]);
return 0;
}
char convert(char b[])
{
int i;
char *psentence[10][1000];
for( i=0; i<10; i++)
{
b[i] = &psentence[i];
return psentence;
}
There are a few things wrong so bear with me:
int main() {
char array[10][1000]; // Ok, Note that you will use these ~10 kB of data for as long as the program runs.
int i;
for(i=0; i < 10; i++) {
printf(" Please input a string value");
fgets( array[i], 1000, stdin);
}
// This next line has an error in your code, what you are saying here is:
// Send in the 11th string in "array", however array only has
// 10 strings so this will not work as intended.
// If you wish to send in ALL 10 strings just write convert(array)
// and change the function prototype to char ** convert(char array[][1000]).
// Please note that the the [1000] must always match between the function and a
// Statically allocated two-dimensional array. (One reason to prefer pointers
// in this use-case.
convert(array);
return 0;
}
I'm slightly uncertain about what you are actually trying to achieve here... Do you want to copy psentence into b? If so, what do you want psentence to be? Currently it is simply uninitialized data, which will appear like garbage in your code. If you instead want to convert the two dimensional array into an array of char-pointers, that makes a little more sense. So I will go with that...
Assumptions
You do not know how many lines will be converted.
The argument b[][] will live longer than the return value, therefore we do not need to duplicate the data.
Below are two different implementations performing basically the same thing, filling an array with pointers to the strings in b.
This version takes the array to store the elements as a parameter,
This is required because we need the pointer-array to live even after we return from the function.
Also note that the return-value can be changed to void in this case.
void convert(char* ptr_arr[], char b[][1000], int lines ) {
int i;
for( i=0; i<lines; i++) {
ptr_arr[i] = b[i]; // b[i] yields a pointer to the i'th line.
}
}
This version returns a new dynamically allocated array with the pointers.
Note that the allocated data must later be freed with a call to free.
Google dynamic memory allocation in C for more information.
char** convert(char b[][1000], int lines ) {
char **ptr_arr = malloc(sizeof(char*)*lines +1 ); // Allocate enough space for lines +1 pointers.
// Check that allocation succeeded.
if (ptr_arr == NULL) return NULL;
int i;
for( i=0; i<lines; i++) {
ptr_arr[i] = b[i];
}
// Use a NULL ptr to mark the last element (this is optional)
ptr_arr[lines] = NULL;
// Finally, return the new table:
return ptr_arr;
}
Hi friends i am trying to copy a entire structure to another structure. When i compile, i don't get errors....when i print displays some garbage value....please guide me...Thanks!
In two different functions i am trying to add values and print it. My first function is "read_list"...in this i am getting the name of the student and marks inserted from the user.
My second functions is "print_list", using this function i am printing the details of student.
Please guide me to a tutorials where i can find few quite interesting examples using structure's in C
#include<stdio.h>
typedef struct _student
{
char name[50];
unsigned int mark;
} student;
void print_list(student list[], int size);
void read_list(student list[], int size);
int main(void)
{
const int size = 3;
student list_first[size]; //first structre
student list_second[size]; //second structre of same type
read_list(list_first, size); //list_first structer fills with values
print_list(list_first, size); //to check i have printed it here
//Now as i knew that my first struct is filled with data .....so now i wanted to copy it
list_second[size] = list_first[size]; //cpoid from one struct to another
printf("Second list is copied from another struct: \n");
print_list(list_second, size); //Tried to print it here ....
system("pause");
return 0;
}
void read_list(student list[], int size)
{
unsigned int i;
printf("Please enter the info:\n");
for(i = 0; i<size; i++)
{
printf("\nname: ");
scanf("%s",&list[i].name);
printf("\nMark: ");
scanf("%d",&list[i].mark);
}
}
void print_list(student list[], int size)
{
unsigned int i;
for(i=0; i<size; i++)
{
printf("Name: %s\t %d\n",list[i].name,list[i].mark);
}
}
Use memcpy() to copy the arrays:
memcpy(list_second, list_first, sizeof(list_first));
The current assignment attempt is incorrect as it is accessing beyond the bounds of the array (arrays have zero based indexes, so valid indexes run from 0 to size - 1) causing undefined behaviour:
list_second[size] = list_first[size];
Even if it was not, it would only copy one of the elements and is the reason garbage is printed because list_second is uninitialized.
list_second[size] = = list_first[size];
is undefined behaviour as the allowed indices to list_second and list_first are 0 to size - 1. So using size as index you try to address the array element behind the last element.
To copy all array members use:
for (size_t sizeCnt = 0; sizeCnt < size, ++ sizeCnt)
{
list_second[sizeCnt] = list_first[sizeCnt];
}
As a note: To access array elements, as well as to address memory the preferred integer type is size_t, which is defined to be an unsigned type to be wide enough to access the platforms address space.
change list_second[size] = list_first[size]; to memcpy(list_second,list_first,sizeof(list_first)); you need to copy an array of structure, not a element. also array[3] means an array of 3 elements. So 2 is the maximum index allowed. array[3] is invalid