I am new to c programming. Could anyone please tell me what's wrong with
the following program?
typedef struct Person_s
{
int age;
char name[40];
} Person_t;
int process_list(int *countReturned, Person_t **p_list)
{
Person_t *rowPtr=0;
//the actual program will fethc data from DB
int count =1;
if(!((*p_list) = (Person_t *) malloc(sizeof(Person_t))))
{
return -1;
}
rowPtr = *p_list;
rowPtr[count-1].age =19;
strcpy(rowPtr[count-1].name,"Prince Dastan");
*countReturned = count;
return 0;
}
int main(int argc, char *argv[])
{
Person_t *tmpPerson=0;
Person_t **p_list=0;
int *count=0;
int i;
process_list(count,p_list);
tmpPerson = *p_list;
for(i=0; i< *count; i++)
{
printf("Name: %s , age: %d\n",tmpPerson->name,tmpPerson->age);
tmpPerson++;
}
//free(tmpPerson);
return 0;
}
Your problem is that you're setting the pointers to point to NULL (0), then dereferencing them. You are not allowed to dereference NULL. Want you want is more like this:
int main(int argc, char *argv[])
{
Person_t tmpPerson;
Person_t *p_list=0;
int count;
int i;
process_list(&count, &p_list);
tmpPerson = *p_list;
// and so on...
The & is the "address-of" operator, which returns a pointer to the variable's address. So this passes a pointer to count and p_list, which your function then uses to set those variables, which appears to be what you want to do.
You should have in main:
Person_t *p_list=0;
...
process_list(count, &p_list);
The code as written passes in 0 to process_list, and then you have:
*0 = (Person_t *)malloc(...);
This causes 0 to be dereferenced, and your code will crash.
The value of p_list as you enter the function is 0. If you dereference 0 you get a Bus Error.
if(!((*p_list) = (Person_t *) malloc(sizeof(Person_t))))
(90% of C problems are caused by dereferencing a null pointer, just like 90% of Java problems are caused by a misconfigured classpath. :-)
Related
I apologise if this seems simple, I'm still learning and I'm new to C.
I have this as my struct:
struct Game{
char id;
char name[50];
char genre[20];
char platform[15];
char company[30];
float price;
int quantity = 10;
};
And this declared as a struct array:
struct Game gList[30];
I have a function where I'm passing all of 'gList' to search through values in the gList[i].name variables.
So my question is, is it possible to send only the gList[i].name part of the struct to the function as a parameter?(ie All the 30 name values only).
No.
But you could make an array of pointers that point to the name field and pass it to the function:
char* ptr[30];
for(int i = 0; i < 30; i++)
ptr[i] = gList[i].name;
func(ptr);
No you can't. However, you can pass iterators to functions just fine. Typical pattern:
struct context { struct Game *gList; int nList; int i; }
char *iter_names(void *baton)
{
struct context *ptr = baton;
if (ptr->i == ptr->nList) return NULL;
return ptr->gList[ptr->i++].name;
}
void wants_name_array(char (*nextname)(void *), void *baton)
{
while (char *name = nextname(baton))
{
printf("%s\n", name);
/* and whatever else you are doing */
}
}
/* ... */
struct context baton = { gList, 30, 0 };
wants_name_array(iter_names, baton);
Yeah it looks kinda bad. Thankfully, gcc has an extension that makes this much better.
void wants_name_array(char (*nextname)())
{
while (char *name = nextname())
{
printf("%s\n", name);
/* and whatever else you are doing */
}
}
/* ... */
{
int i = 0;
char *nextname()
{
if (i == 30) return NULL;
return gList[i++].name;
}
wants_name_array(nextname);
}
When using this particular gcc extension, never ever return nested functions. Undefined behavior.
There are quite a few topics on this subject but I haven't been able to find a solution that's worked for me; I am getting a segmentation fault whenever I try to change student_t.member->name. Below is the typedef structure that I am required to use:
typedef struct degree_t degree_t;
typedef struct student_t student_t;
struct degree_t {
student_t* member;
int course_id;
}
struct student_t {
char* name;
int age;
}
int main(int argc, char* argv[]) {
student_t *students = malloc(sizeof(student_t) * 3);
degree_t *degrees = malloc(sizeof(degree_t));
for (int i=0; i<3; i++) {
degrees[i].course_id = 1;
degrees[i].member->name = "Bob";
}
return 0;
}
I can change degrees[i].course_id perfectly fine, but whenever I try to change degrees[i].member -> name, I get a segmentation fault.
GDB indicates that this is a result of the line degrees[i].member->name = "Bob", but I'm don't understand why, and I don't know how to effectively change the value of degrees[i].member->name
Oops, you managed to place four errors in that small program.
The signature of main() should be main(int argc, char *argv[]). argv is an array of strings found on the command line.
You allocate memory for one degree, but in the for-loop you initialize three of them. This leads to a heap corruption.
You don't initialize degrees->member, but use it.
You allocate memory for three students, but don't use it.
Try this:
struct degree_t {
student_t* member;
int course_id;
}
struct student_t {
const char* name;
int age;
}
int main(int argc, char* argv[]) {
degree_t *degrees = malloc(3 * sizeof(degree_t));
for (int i=0; i<3; i++) {
degrees[i].course_id = 1;
degrees[i].member = malloc(sizeof(student_t));
degrees[i].member->name = "Bob";
degrees[i].member->age = 23;
}
return 0;
}
I'm trying to write a C program that gathers all structures passing a specific condition into an array.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Book {
char title[20];
unsigned int published;
char authors[50];
unsigned int pages;
};
unsigned int get_books_from(unsigned int year, int length, struct Book data[], struct Book results[]);
int main(int argc, char* argv[]) {
struct Book data[5];
// Init book pool inside data
struct Book books[0];
unsigned int books_count = get_books_from(1973, 5, data, books);
return 0;
}
unsigned int get_books_from(unsigned int year, int length, struct Book data[], struct Book results[]) {
results = (struct Book*) malloc(sizeof(struct Book));
unsigned int results_count = 0;
int i;
for (i = 0; i < length; i++) {
if (data[i].published == year) {
*(results + results_count) = data[i];
results = (struct Book*) realloc(results, (++results_count + 1) * sizeof(struct Book));
}
}
return results_count;
}
The logic seems to be working fine, however when trying to access the books array contents outside of the get_books_from function (where it's called results), all the data becomes corrupted. Some of the original data is still there but not in the right places, it looks as if the data got shifted. I checked the pointers to both books and results and it appears that those variables do not point to the same place in memory after the function finishes. What could be the problem?
Your get_books_from changes the value of results here:
results = (struct Book*) realloc(results, (++results_count + 1) * sizeof(struct Book));
But it provides no way for the caller to get the new value of results.
Worse, you call get_books_from with data, which was allocated on the stack in main. You can't realloc it. As the documentation for realloc says, the pointer you are attempting to reallocate must been returned by a previous call to malloc, calloc, or realloc. Fortunately, you ignore that value. But that renders the struct Book data[5]; in main incomprehensible. Why allocate space on the stack?
In addition to the other answer:
You probably want something like this (untested, non error checking code, declarations and #includes ommited for brevity):
unsigned int get_books_from(unsigned int year, int length, struct Book data[], struct Book **results);
int main(int argc, char* argv[]) {
struct Book data[5];
// Init book pool inside data
struct Book *books;
unsigned int books_count = get_books_from(1973, 5, data, &books);
return 0;
}
unsigned int get_books_from(unsigned int year, int length, struct Book data[], struct Book **results) {
*results = (struct Book*) malloc(sizeof(struct Book));
unsigned int results_count = 0;
int i;
for (i = 0; i < length; i++) {
if (data[i].published == year) {
*(*results + results_count) = data[i];
*results = (struct Book*) realloc(*results, (++results_count + 1) * sizeof(struct Book));
}
}
return results_count;
}
Say I have a simple struct, such as this one:
struct myStruct {
uint8_t arr[10];
};
All I want to be able to do is to modify the contents of that array. However, it seems that I cannot assign the array directly (ie, I can't do something like pointerToThisStruct->arr = anArrayofSizeTen).
So here is my main method:
int main(int argc, char **argv) {
uint8_t test[10] = {0};
myStruct *struc;
struc->arr = test; //can't do this
memcpy(struc->arr, test, sizeof(test));
}
Now, I understand that direct copying over won't work, but why is memcpy also giving me a segfault? How exactly am I supposed to modify the struct array?
You need to declare an actual myStruct. Not a pointer to one. Declaring a pointer to one doesn't actually allocate any memory for the struct.
#include <stdio.h>
#include <stdint.h>
#include <string.h>
struct myStruct {
uint8_t arr[10];
};
int main(int argc, char **argv) {
int i;
uint8_t test[10] = {0,1,2,3,4,5,6,7,8,9};
struct myStruct struc;
memcpy(struc.arr, test, sizeof(struc.arr));
printf("struc.arr[] = ");
for( i=0; i < sizeof(test); i++ )
{
printf("%d ", struc.arr[i]);
}
printf("\n");
return( 0 );
}
You are getting a segmentation fault because you didn't allocate your struct pointer.
int main(int argc, char **argv) {
uint8_t test[10] = {0};
struct myStruct *struct = malloc(sizeof(struct myStruct));
if (!struc)
return -1;
memcpy(struc->arr, test, sizeof(test));
free(struc);
return 0;
}
But, as #Chimera mentioned, you perfectly can not use a point and directly a heap-allocated structure, and access to its inner fields with the . operator
I would like to read a file that has the sample number, values and status(1.1, 23,0). I used a Struct to hold that information. I will pass the function struct array and the file location.
#include <stdio.h>
struct Data_point
{
long sampleNumber;
double value;
int status;
};
int filldata(struct Data_point *a, const char *filelocation)
{
FILE *f;
if((f=fopen(filelocation,"r"))==NULL)
{
printf("You cannot open");
}
fscanf(f, "%ld%lf%d", a.sampleNumber, a.value, a.status);
}
int main(void)
{
struct Data_point data[10];
filldata(data, "/home/alexchan/IntrotoC/rec11/dataPoints.txt");
return 0;
}
But, I got an error saying, "request for member not a structure"...
One problem is that the filldata() is taking a pointer argument. So you use -> to address members not ".". So a.sampleNumber should be a->sampleNumber for example.
Another issue is that filldata() is reading in a single struct, but you are passing it the pointer to the top of the array, which is synonymous with &(data[0]). So this function will just overwrite that first element if you call it repeatedly (which you didn't). If you call it in a loop you will need to pass it in pointers to the individual array members:
for(int i = 0; i < 10; ++i){
filldata(&(data[i]), "/home/alexchan/IntrotoC/rec11/dataPoints.txt");
}
You could actually use data + i as the first arg instead of &(data[i]) but I like the latter as I find it more readable.
struct Data_point *a is your function arugument and you are passing data which is a array. So basically you are trying to acess members from a array which is not a struct.
May be
for( int i=0; i<10;++i)
filldata(data[i],.....)
and
int filldata( struct Data_point a,...) //as you are using a.
fscanf requires a pointer-to-data for each passed argument. Use the AddressOf operator & to get a reference to each struct member:
int filldata(const char *filelocation, struct Data_point *a, int nElements)
{
int n = 0;
FILE *f = fopen(filelocation, "r");
if(f)
{
while (fscanf(f, "(%ld,%lf,%d)", &(a[n].sampleNumber), &(a[n].value), &(a[n].status)) == 3 && n < nElements)
n++;
fclose(f);
}
else { printf("Unable to open '%s'\n", filelocation); }
return n;
}
Now, this function is slightly different to yours. You need to tell it how long the array you're passing in as the "a" parameter is. It will return the number of successfully filled entries.
i.e
int main(int argc, char **argv)
{
struct Data_point data[10];
int n = filldata("C:\\Users\\254288b\\temp.txt", data, sizeof(data) / sizeof(struct Data_point));
printf("%d Data_point's were filled successfully.\n\n", n);
for(int i = 0; i < n; i++)
{
printf("Sample Number: %ld\n", data[i].sampleNumber);
printf("Value: %lf\n", data[i].value);
printf("Status: %d\n", data[i].status);
printf("----------------------------\n");
}
return 0;
}
Do note, my pattern for fscanf expects your file to be like:
(100,1.1,10)(200,2.2,20)(300,3.3,30)(400,4.4,40)
Each set is enclosed in parenthesis.