Passing entire structure to a function and display the contents C - c

I have been stuck on this for a while now.The program reads lines from a text file into array of structures. Here is a few lines so you get an idea of what is being stored into array of structures.
A|Baltimore Orioles|Oriole Park|333 West Camden Street|Baltimore|MD|21201|(410) 685-9800|orioles.com
N|Washington Nationals|Nationals Park|1500 South Capitol Street, SE|Washington|DC|20003-1507|(202) 675-6287|nationals.com
There is no problem when it comes to loading the arrays with correct data. I tested the contents using this piece of code and it displays correct data.
scanf("%i",&userChoice);
if(userChoice == 1){
for(index=0; index<count; index++)
{
if(strcmp("A", teams[index].leagueName)== 0)
{
americanLeague(&teams[index]);
}
}
}
The program has a main menu and option 1 is to display all teams from American League or "A" from text file. Now I don't want the for loop/if statement to run in main function.I want it just to run the if statement for userchoice and call the americanLeague function. Here is my attempt
scanf("%i",&userChoice);
if(userChoice == 1){
americanLeague(&teams[0]);
}
This just calls americanLeague function
void americanLeague(team_t *aTeamPtr)
{
int index;
for(index=0; index<=MAX_TEAMS; index++){
if(strcmp("A", aTeamPtr[index].leagueName)== 0)
{
printf("LEAGUE:%s TEAM:%s PARKNAME:%s ADDRESS:%s CITY:%s STATE:%s ZIPCODE:%s PHONE#:%s WEBADDRESS:%s\n\n",
aTeamPtr[index].leagueName, aTeamPtr[index].teamName,
aTeamPtr[index].parkName, aTeamPtr[index].teamAddress,
aTeamPtr[index].teamCity, aTeamPtr[index].teamState,
aTeamPtr[index].zipCode, aTeamPtr[index].phoneNumber,
aTeamPtr[index].webAddress);
}
}
}
Here is my attempt to try and display teams info passing array of structures into another function.The code doesn't work, but it doesn't give me any errors it just outputs blank spaces.I will also add structure and how I read file just in case.
typedef struct
{
char leagueName[LEAGUE_NAME + 1];
char teamName[LEN_NAME + 1];
char parkName[PARK_NAME + 1];
char teamAddress[TEAM_ADDRESS + 1];
char teamCity[TEAM_CITY + 1];
char teamState[TEAM_STATE + 1];
char zipCode[ZIP_CODE + 1];
char phoneNumber[PHONE_NUMBER + 1];
char webAddress[WEB_ADDRESS + 1];
} team_t;
int main(void)
{
FILE * filePtr;
int index, count;
char line[LEN_LINE + 1];
char repeat;
team_t teams[MAX_LINES];
filePtr = fopen("MLBteams.txt", "r");
if(filePtr == NULL)
{
printf("Unable to open file.\n");
}
else
{
index = 0;
while(index<MAX_LINES && fgets(line, LEN_LINE, filePtr))
{
if(9 == sscanf(line,"%5[^|]| %40[^|]| %35[^|]| %40[^|]| %30[^|]| %5[^|]| %10[^|]| %30[^|]| %25[^\n]", teams[index].leagueName, teams[index].teamName,
teams[index].parkName, teams[index].teamAddress,
teams[index].teamCity, teams[index].teamState,
teams[index].zipCode, teams[index].phoneNumber,
teams[index].webAddress)
)
{
index++;
}
}
fclose(filePtr);
count = index;
There is no problem when reading correct data into array of structures.I already tested the output several times within main function.Anyways any help would be much appreciated.

You're apparently passing an array (or pointer) to a function that also treats it as a pointer to a single instance. You can see the difference in your code where you do aTeamPtr[index].leagueName but also aTeamPtr->leagueName.
Which one do you want?
Consider this code and its output:
int size = 10;
struct iint {
int i;
};
void foo(struct iint* i) {
for (int j = 0; j < size; ++j) {
printf("%d", i[j].i);
}
printf("\n%d\n", i->i);
}
int main() {
struct iint i[size];
for (int j = 0; j < size; ++j) {
i[j].i = j;
}
foo(i);
return 0;
}
// Output:
// 0123456789
// 0
That's because a pointer to an array points at the first element. C doesn't care if you choose to use them interchangeably.

Related

Segmentation Fault when My Code Executes the printf() in c

below I have posted my code. When I compile I receive no errors, and only one warning about variables I haven't used yet. the code works all the way to the line in code where it starts to print. I have tested all the sections and I believe that one is at fault. please let me know what I am doing wrong so I can fix it.
#include <stdio.h>
#include <string.h>
#define NUM_LINES 37
#define LINE_LENGTH 60
void select_sort_str(char list[NUM_LINES][LINE_LENGTH], int n);
int alpha_first(char list[NUM_LINES][LINE_LENGTH], int min_sub, int max_sub);
int main (void){
//store each line in an array of strings
FILE *inp;
FILE *outp;
char hurr[NUM_LINES][LINE_LENGTH];
;
inp = fopen("hurricanes.csv","r");
outp = fopen("out.txt","w");
//read in lines from file
for (int i = 0; i<NUM_LINES; i++){
fgets(hurr[i], LINE_LENGTH, inp);
}
inp = fopen("hurricanes.cvs","r");
//printf("%s", hurr[0]);
//define function
select_sort_str(hurr, NUM_LINES);
return(0);
}
int
alpha_first(char list[NUM_LINES][LINE_LENGTH], // input - array of pointers to strings
int min_sub, // input - min and max subscripts of
int max_sub) // portion of list to consider
{
int first, i;
first = min_sub;
for (i = min_sub + 1; i <= max_sub; ++i) {
if (strcmp(list[i], list[first]) < 0) {
first = i;
}
}
return (first);
}
/*
* Orders the pointers in an array list so they access strings in
* alphabetical order
* Pre: first n elements of list reference string of uniform case;
* n >= 0
*/
void
select_sort_str(char list[NUM_LINES][LINE_LENGTH], // input/output - array of pointers being
// ordered to acces strings alphabetically
int n) // input - number of elements to sort
{
int fill, // index of element to contain next string in order
index_of_min; // index of next string in order
char *temp;
char temp1[NUM_LINES][LINE_LENGTH];
for (fill = 0; fill < n - 1; ++fill) {
index_of_min = alpha_first(list, fill, n - 1);
if (index_of_min != fill) {
temp = list[index_of_min];
list[index_of_min][LINE_LENGTH] = list[fill][LINE_LENGTH];
strncpy(temp1[index_of_min], list[index_of_min], LINE_LENGTH);
temp1[fill][LINE_LENGTH] = *temp;
}
}
char *name;
char *cat = 0;
char *date;
for (int i = 0; i<NUM_LINES; i++){
name = strtok(NULL, ",");
cat = strtok(NULL, "h");
date = strtok(NULL, " ");
printf("%s %s %s\n", name, cat, date);
}
// for( int i =0; i<NUM_LINES; i++){
// printf("%s", list[i]);
// }
}
The only first parameter you ever pass to strtok is NULL. You never actually give it anything to parse. Did you perhaps mean strtok(temp1[i], ",");?
Also, why no error checking? It's much easier to find bugs in code with error checking.

Try to split string but got messy substrings

I try to split one string to 3-gram strings. But turns out that the resulting substrings were always messy. The length and char ** input... are needed, since I will use them as args later for python calling the funxtion.
This is the function I wrote.
struct strArrIntArr getSearchArr(char* input, int length) {
struct strArrIntArr nameIndArr;
// flag of same bit
int same;
// flag/index of identical strings
int flag = 0;
// how many identical strings
int num = 0;
// array of split strings
char** nameArr = (char **)malloc(sizeof(char *) * (length - 2));
if ( nameArr == NULL ) exit(0);
// numbers of every split string
int* valueArr = (int* )malloc(sizeof(int) * (length-2));
if ( valueArr == NULL ) exit(0);
// loop length of search string -2 times (3-gram)
for(int i = 0; i<length-2; i++){
if(flag==0){
nameArr[i - num] = (char *)malloc(sizeof(char) * 3);
if ( nameArr[i - num] == NULL ) exit(0);
printf("----i------------%d------\n", i);
printf("----i-num--------%d------\n", i-num);
}
flag = 0;
// compare splitting string with existing split strings,
// if a string exists, it would not be stored
for(int k=0; k<i-num; k++){
same = 0;
for(int j=0; j<3; j++){
if(input[i + j] == nameArr[k][j]){
same ++;
}
}
// identical strings found, if all the three bits are the same
if(same == 3){
flag = k;
num++;
break;
}
}
// if the current split string doesn't exist yet
// put current split string to array
if(flag == 0){
for(int j=0; j<3; j++){
nameArr[i-num][j] = input[i + j];
valueArr[i-num] = 1;
}
}else{
valueArr[flag]++;
}
printf("-----string----%s\n", nameArr[i-num]);
}
// number of N-gram strings
nameIndArr.length = length- 2- num;
// array of N-gram strings
nameIndArr.charArr = nameArr;
nameIndArr.intArr = valueArr;
return nameIndArr;
}
To call the function:
int main(int argc, const char * argv[]) {
int length = 30;
char* input = (char *)malloc(sizeof(char) * length);
input = "googleapis.com.wncln.wncln.org";
// split the search string into N-gram strings
// and count the numbers of every split string
struct strArrIntArr nameIndArr = getSearchArr(input, length);
}
Below is the result. The strings from 17 are messy.
----i------------0------
----i-num--------0------
-----string----goo
----i------------1------
----i-num--------1------
-----string----oog
----i------------2------
----i-num--------2------
-----string----ogl
----i------------3------
----i-num--------3------
-----string----gle
----i------------4------
----i-num--------4------
-----string----lea
----i------------5------
----i-num--------5------
-----string----eap
----i------------6------
----i-num--------6------
-----string----api
----i------------7------
----i-num--------7------
-----string----pis
----i------------8------
----i-num--------8------
-----string----is.
----i------------9------
----i-num--------9------
-----string----s.c
----i------------10------
----i-num--------10------
-----string----.co
----i------------11------
----i-num--------11------
-----string----com
----i------------12------
----i-num--------12------
-----string----om.
----i------------13------
----i-num--------13------
-----string----m.w
----i------------14------
----i-num--------14------
-----string----.wn
----i------------15------
----i-num--------15------
-----string----wnc
---i------------16------
----i-num--------16------
-----string----ncl
----i------------17------
----i-num--------17------
-----string----clnsole
----i------------18------
----i-num--------18------
-----string----ln.=C:
----i------------19------
----i-num--------19------
-----string----n.wgram 馻绚s
----i------------20------
----i-num--------20------
-----string----n.wgram 馻绚s
-----string----n.wgram 馻绚s
-----string----n.wgram 馻绚s
-----string----n.wgram 馻绚s
-----string----n.wgram 馻绚s
-----string----n.oiles(騛窑=
----i------------26------
----i-num--------21------
-----string----.orSModu鯽蓼t
----i------------27------
----i-num--------22------
-----string----org
under win10, codeblocks 17.12, gcc 8.1.0
You are making life complicated for you in several places:
Don't count backwards: Instead of making num the count of duplicates, make it the count of unique trigraphs.
Scope variable definitions in functions as closely as possible. You have several uninitialized variables. You have declared them at the start of the function, but you need them only in local blocks.
Initialize as soon as you allocate. In your code, you use a flag to determine whather to create a new string. The code to allocate he string and to initialize it are in different blocks. Those blocks have the same flag as condition, but the flag is updated in between. This could lead to asynchronities, even to bugs when you try to initialize memory that wasn't allocated.
It's probably better to keep the strings and their counts together in a struct. If anything, this will help you with sorting later. This also offers some simplification: Instead of allocating chunks of 3 bytes, keep a char array of four bytes in the struct, so that all entries can be properly null-terminated. Those don't need to be allocated separately.
Here's an alternative implementation:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct tri {
char str[4]; // trigraph: 3 chars and NUL
int count; // count of occurrences
};
struct stat {
struct tri *tri; // list of trigraphs with counts
int size; // number of trigraphs
};
/*
* Find string 'key' in list of trigraphs. Return the index
* or in the array or -1 if it isn't found.
*/
int find_trigraph(const struct tri *tri, int n, const char *key)
{
for (int i = 0; i < n; i++) {
int j = 0;
while (j < 3 && tri[i].str[j] == key[j]) j++;
if (j == 3) return i;
}
return -1;
}
/*
* Create an array of trigraphs from the input string.
*/
struct stat getSearchArr(char* input, int length)
{
int num = 0;
struct tri *tri = malloc(sizeof(*tri) * (length - 2));
for(int i = 0; i < length - 2; i++) {
int index = find_trigraph(tri, num, input + i);
if (index < 0) {
snprintf(tri[num].str, 4, "%.3s", input + i); // see [1]
tri[num].count = 1;
num++;
} else {
tri[index].count++;
}
}
for(int i = 0; i < num; i++) {
printf("#%d %s: %d\n", i, tri[i].str, tri[i].count);
}
struct stat stat = { tri, num };
return stat;
}
/*
* Driver code
*/
int main(void)
{
char *input = "googleapis.com.wncln.wncln.org";
int length = strlen(input);
struct stat stat = getSearchArr(input, length);
// ... do stuff with stat ...
free(stat.tri);
return 0;
}
Footnote 1: I find that snprintf(str, n, "%.*s", len, str + offset) is useful for copying substrings: The result will not overflow the buffer and it will be null-terminated. There really ought to be a stanard function for this, but strcpy may overflow and strncpy may leave the buffer unterminated.
This answer tries to fix the existing code instead of proposing alternative/better solutions.
After fixing the output
printf("-----string----%s\n", nameArr[i-num]);
in the question, there is still another important problem.
You want to store 3 characters in nameArr[i-num] and allocate space for 3 characters. Later you print is as a string in the code shown above. This requires a trailing '\0' after the 3 characters, so you have to allocate memory for 4 characters and either append a '\0' or initialize the allocated memory with 0. Using calloc instead of malloc would automatically initialize the memory to 0.
Here is a modified version of the source code
I also changed the initialization of the string value and its length in main() to avoid the memory leak.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct strArrIntArr {
int length;
char **charArr;
int *intArr;
};
struct strArrIntArr getSearchArr(char* input, int length) {
struct strArrIntArr nameIndArr;
// flag of same bit
int same;
// flag/index of identical strings
int flag = 0;
// how many identical strings
int num = 0;
// array of split strings
char** nameArr = (char **)malloc(sizeof(char *) * (length - 2));
if ( nameArr == NULL ) exit(0);
// numbers of every split string
int* valueArr = (int* )malloc(sizeof(int) * (length-2));
if ( valueArr == NULL ) exit(0);
// loop length of search string -2 times (3-gram)
for(int i = 0; i<length-2; i++){
if(flag==0){
nameArr[i - num] = (char *)malloc(sizeof(char) * 4);
if ( nameArr[i - num] == NULL ) exit(0);
printf("----i------------%d------\n", i);
printf("----i-num--------%d------\n", i-num);
}
flag = 0;
// compare splitting string with existing split strings,
// if a string exists, it would not be stored
for(int k=0; k<i-num; k++){
same = 0;
for(int j=0; j<3; j++){
if(input[i + j] == nameArr[k][j]){
same ++;
}
}
// identical strings found, if all the three bits are the same
if(same == 3){
flag = 1;
num++;
break;
}
}
// if the current split string doesn't exist yet
// put current split string to array
if(flag == 0){
for(int j=0; j<3; j++){
nameArr[i-num][j] = input[i + j];
valueArr[i-num] = 1;
}
nameArr[i-num][3] = '\0';
}else{
valueArr[flag]++;
}
printf("-----string----%s\n", nameArr[i-num]);
}
// number of N-gram strings
nameIndArr.length = length- 2- num;
// array of N-gram strings
nameIndArr.charArr = nameArr;
nameIndArr.intArr = valueArr;
return nameIndArr;
}
int main(int argc, const char * argv[]) {
int length;
char* input = strdup("googleapis.com.wncln.wncln.org");
length = strlen(input);
// split the search string into N-gram strings
// and count the numbers of every split string
struct strArrIntArr nameIndArr = getSearchArr(input, length);
}
This other answer contains more improvements which I personally would prefer over the modified original solution.

Attempting to split and store arrays similar to strtok

For an assignment in class, we have been instructed to write a program which takes a string and a delimiter and then takes "words" and stores them in a new array of strings. i.e., the input ("my name is", " ") would return an array with elements "my" "name" "is".
Roughly, what I've attempted is to:
Use a separate helper called number_of_delimeters() to determine the size of the array of strings
Iterate through the initial array to find the number of elements in a given string which would be placed in the array
Allocate storage within my array for each string
Store the elements within the allocated memory
Include directives:
#include <stdlib.h>
#include <stdio.h>
This is the separate helper:
int number_of_delimiters (char* s, int d)
{
int numdelim = 0;
for (int i = 0; s[i] != '\0'; i++)
{
if (s[i] == d)
{
numdelim++;
}
}
return numdelim;
}
`This is the function itself:
char** split_at (char* s, char d)
{
int numdelim = number_of_delimiters(s, d);
int a = 0;
int b = 0;
char** final = (char**)malloc((numdelim+1) * sizeof(char*));
for (int i = 0; i <= numdelim; i++)
{
int sizeofj = 0;
while (s[a] != d)
{
sizeofj++;
a++;
}
final[i] = (char*)malloc(sizeofj);
a++;
int j = 0;
while (j < sizeofj)
{
final[i][j] = s[b];
j++;
b++;
}
b++;
final[i][j+1] = '\0';
}
return final;
}
To print:
void print_string_array(char* a[], unsigned int alen)
{
printf("{");
for (int i = 0; i < alen; i++)
{
if (i == alen - 1)
{
printf("%s", a[i]);
}
else
{
printf("%s ", a[i]);
}
}
printf("}");
}
int main(int argc, char *argv[])
{
print_string_array(split_at("Hi, my name is none.", ' '), 5);
return 0;
}
This currently returns {Hi, my name is none.}
After doing some research, I realized that the purpose of this function is either similar or identical to strtok. However, looking at the source code for this proved to be little help because it included concepts we have not yet used in class.
I know the question is vague, and the code rough to read, but what can you point to as immediately problematic with this approach to the problem?
The program has several problems.
while (s[a] != d) is wrong, there is no delimiter after the last word in the string.
final[i][j+1] = '\0'; is wrong, j+1 is one position too much.
The returned array is unusable, unless you know beforehand how many elements are there.
Just for explanation:
strtok will modify the array you pass in! After
char test[] = "a b c ";
for(char* t = test; strtok(t, " "); t = NULL);
test content will be:
{ 'a', 0, 'b', 0, 'c', 0, 0 }
You get subsequently these pointers to your test array: test + 0, test + 2, test + 4, NULL.
strtok remembers the pointer you pass to it internally (most likely, you saw a static variable in your source code...) so you can (and must) pass NULL the next time you call it (as long as you want to operate on the same source string).
You, in contrast, apparently want to copy the data. Fine, one can do so. But here we get a problem:
char** final = //...
return final;
void print_string_array(char* a[], unsigned int alen)
You just return the array, but you are losing length information!
How do you want to pass the length to your print function then?
char** tokens = split_at(...);
print_string_array(tokens, sizeof(tokens));
will fail, because sizeof(tokens) will always return the size of a pointer on your local system (most likely 8, possibly 4 on older hardware)!
My personal recommendation: create a null terminated array of c strings:
char** final = (char**)malloc((numdelim + 2) * sizeof(char*));
// ^ (!)
// ...
final[numdelim + 1] = NULL;
Then your print function could look like this:
void print_string_array(char* a[]) // no len parameter any more!
{
printf("{");
if(*a)
{
printf("%s", *a); // printing first element without space
for (++a; *a; ++a) // *a: checking, if current pointer is not NULL
{
printf(" %s", *a); // next elements with spaces
}
}
printf("}");
}
No problems with length any more. Actually, this is exactly the same principle C strings use themselves (the terminating null character, remember?).
Additionally, here is a problem in your own code:
while (j < sizeofj)
{
final[i][j] = s[b];
j++; // j will always point behind your string!
b++;
}
b++;
// thus, you need:
final[i][j] = '\0'; // no +1 !
For completeness (this was discovered by n.m. already, see the other answer): If there is no trailing delimiter in your source string,
while (s[a] != d)
will read beyond your input string (which is undefined behaviour and could result in your program crashing). You need to check for the terminating null character, too:
while(s[a] && s[a] != d)
Finally: how do you want to handle subsequent delimiters? Currently, you will insert empty strings into your array? Print out your strings as follows (with two delimiting symbols - I used * and + like birth and death...):
printf("*%s+", *a);
and you will see. Is this intended?
Edit 2: The variant with pointer arithmetic (only):
char** split_at (char* s, char d)
{
int numdelim = 0;
char* t = s; // need a copy
while(*t)
{
numdelim += *t == d;
++t;
}
char** final = (char**)malloc((numdelim + 2) * sizeof(char*));
char** f = final; // pointer to current position within final
t = s; // re-assign t, using s as start pointer for new strings
while(*t) // see above
{
if(*t == d) // delimiter found!
{
// can subtract pointers --
// as long as they point to the same array!!!
char* n = (char*)malloc(t - s + 1); // +1: terminating null
*f++ = n; // store in position pointer and increment it
while(s != t) // copy the string from start to current t
*n++ = *s++;
*n = 0; // terminate the new string
}
++t; // next character...
}
*f = NULL; // and finally terminate the string array
return final;
}
While I've now been shown a more elegant solution, I've found and rectified the issues in my code:
char** split_at (char* s, char d)
{
int numdelim = 0;
int x;
for (x = 0; s[x] != '\0'; x++)
{
if (s[x] == d)
{
numdelim++;
}
}
int a = 0;
int b = 0;
char** final = (char**)malloc((numdelim+1) * sizeof(char*));
for (int i = 0; i <= numdelim; i++)
{
int sizeofj = 0;
while ((s[a] != d) && (a < x))
{
sizeofj++;
a++;
}
final[i] = (char*)malloc(sizeofj);
a++;
int j = 0;
while (j < sizeofj)
{
final[i][j] = s[b];
j++;
b++;
}
final[i][j] = '\0';
b++;
}
return final;
}
I consolidated what I previously had as a helper function, and modified some points where I incorrectly incremented .

Initializing Strings in an Array of Sturts within a Struct

I have a struct gradebook with(among other things) an array of student structs that has two string fields
#define MAX_NAME_LEN 50
#define MAX_EMAIL_LEN 80
#define MAX_NUMBER_OF_STUDENTS 200
#define MAX_NUMBER_OF_ASSIGNMENTS 100
typedef struct students {
char *name;
char *email;
} Students;
typedef struct gradebook {
int number_of_students;
Students students[MAX_NUMBER_OF_STUDENTS];
int number_of_assignments;
char assignments[MAX_NUMBER_OF_ASSIGNMENTS][(MAX_NAME_LEN + 1)];
int scores[MAX_NUMBER_OF_STUDENTS][MAX_NUMBER_OF_ASSIGNMENTS];
} Gradebook;
I have an initialization function
int init_gradebook(Gradebook *book) {
int row, col, ndx, count;
book->number_of_students = 0;
count += book->number_of_students;
for(ndx = 0; ndx < MAX_NUMBER_OF_STUDENTS; ndx++) {
book->students[ndx].name = 0;
book->students[ndx].email = 0;
}
book->number_of_assignments = 0;
count += book->number_of_assignments;
for(row = 0; row < MAX_NUMBER_OF_ASSIGNMENTS; row++) {
for(col = 0; col < (MAX_NAME_LEN + 1); col++) {
book->assignments[row][col] = 0;
count += book->assignments[row][col];
}
}
for(row = 0; row < MAX_NUMBER_OF_STUDENTS; row++) {
for(col = 0; col < MAX_NUMBER_OF_ASSIGNMENTS; col++) {
book->scores[row][col] = 0;
count += book->scores[row][col];
}
}
if (count == 0) {
return 1;
} else {
return 0;
}
}
and I need to then insert, into those two string fields, the passed in strings, with my add_student function.
int add_student(Gradebook *book, char *nom, char *mail) {
int ndx, count;
if (book->number_of_students == 0) {
book->students[(book->number_of_students)].name = malloc(sizeof(51));
book->students[(book->number_of_students)].email = malloc(sizeof(81));
strcpy(book->students[(book->number_of_students)].name, nom);
strcpy(book->students[(book->number_of_students)].email, mail);
book->number_of_students++;
} else {
for (ndx = 0; ndx < book->number_of_students; ndx++) {
book->students[(book->number_of_students)].name = malloc(sizeof(51));
book->students[(book->number_of_students)].email = malloc(sizeof(81));
strcpy(book->students[(book->number_of_students)].name, nom);
strcpy(book->students[(book->number_of_students)].email, mail);
book->number_of_students++;
}
}
return 1;
}
My code compiles, but when I run it with the main function, I get a seg fault. The add_student function is what I am ultimately trying to do (copy the given string into book->student[ndx].name) If you need to see the main file or the gradebook.h file, let me know.
Edit: Thanks to all of you, this issue has been solved. The main problem, as abginfo pointed out, was my If Else + the For loop inside of it. But now I have other problems further along in my program. Haha, Thank You.
From what portion of your code I can see, I'm going to make the assumption that the init_gradebook function takes a non allocated reference to gradebook and attempts to initialize it.
In this case the gradebook reference you have has no memory allocated to it just yet. Try using the malloc() function to assign the required memory to your gradebook reference before attempting to initialize the rest of its variables.
gb = (Gradebook*)malloc(sizeof(*Gradebook));
I've changed the variable name to avoid any confusion.
To supplement varevarao's answer, you should allocate everything explicitly as a matter of habit instead of relying on segfaults to tell you something's not allocated. (Not that you necessarily do!) Messing with unallocated memory is undefined behavior, so in some cases this code does not trigger an error -
int main (void) {
Gradebook mybook;
init_gradebook(&mybook);
printf("there are %i students\n", mybook.number_of_students);
add_student(&mybook, "blerf", "blerf#gmail.com");
printf("now there are %i students\n", mybook.number_of_students);
printf("%s has an email address of %s\n", mybook.students[0].name, mybook.students[0].email);
return 0;
}
returned (on my machine)
there are 0 students
now there are 1 students
blerf has an email address of blerf#gmail.com

Access to a specific element on an array using pointers C

I am working to replace '.' by '::' in a phrase.
I am given a phrase with 30 caracteres, without using other array. I would like to access to the last element using a pointer.
However,
First I count the dots in my phrase.
actualSize= 0; i= 0; dotNumb= 0;
while (i<actualSize){
if (tab[i]=='.') dotNumb++
i++
}
Now I should start by the end; whenever I find an element I move it, whenever I find a '.' I make an operation two times, by copying ':' two times.
Now I need to access to this element tab[dotNumb+actualSize]
Can I do it this way, or should I use pointers .
int newSize = dotNumb+actualSize ;
int j=newSize ;
int cursor=actualSize;
while (j>0){
if (tab[i]!='.') {tab[j]=tab[cursor]; }
else{tab[j]=':';tab[--j]=':';}
cursor--; j--;
}
The code you wrote does not work, (you made some typos, for example actualSize is set to 0 so the loop counting the dots will never execute. and the logic of your code would delete the character preceding a dot in the original array). You probably want something like that:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void) {
char *tab = malloc(30 + 1);
if (tab == NULL) {
return -1;
}
strcpy(tab, "123456789.123456789.123456789.");
printf("Original string: %s\n", tab);
size_t actualSize = strlen(tab);
int dotNumb = 0;
for (int i = 0; i < actualSize; i++) {
if (tab[i]=='.') {
dotNumb++;
}
}
const size_t newSize = dotNumb + actualSize + 1;
tab = realloc (tab, newSize);
if (tab == NULL) {
/* leak memory previously allocated in tab */
return -1;
}
tab[newSize] = '\0'; /* termination character */
int j = newSize ;
for (size_t cursor = actualSize; cursor > 0; cursor--) {
if (tab[cursor] != '.') {
tab[j--] = tab[cursor];
}
else {
tab[j--] = ':';
tab[j--] = ':';
}
}
printf("Modified string: %s\n", tab);
return 0;
}
You can test the code here:
http://ideone.com/YOxJKo

Resources