Pointer to structure in C - c

How can I display the stored values via pointer, my code outputs to NULL. I've already tried assigning the struct emp to ptr before the 2nd loop but it won't run.
struct rec {
char *Name;
}emp[100];
int main() {
int x;
int i;
struct rec *ptr = NULL;
ptr = emp;
printf("Enter Number of Clients: ");
scanf("%d", &x);
getchar();
for(i=0; i!=x; i++){
printf("Enter Name: ");
scanf("%[^\n]", &ptr->Name);
getchar();
ptr++;
printf("\n");
}
i = 0;
while(i!=x){
printf("Name is: %s\n", *ptr->Name);
i++;
ptr++;
}
If the code iterates twice it prints
Name: (NULL)
Name: (NULL)

How can I display the stored values via pointer, my code outputs to NULL. I've already tried assigning the struct emp to ptr before the 2nd loop but it won't run.
There are several issues in your code which are listed below:
You need to re-initialize your ptr pointer to the beginning of the array emp after the first loop.
ptr = emp;
Second one being data member name of your struct emp. It is just a pointer and it doesn't point towards a valid memory address where you can save user input cstring. Either you need to allocate the memory dynamically using malloc or use statically allocated memory just like shown below. However, you can have buffer overflow if you input characters more than DEFAULT_NAME_SIZE (including /0 character).
%[^\n] matches a char *, not a char **. You need to use scanf("%[^\n]", ptr->Name); not scanf("%[^\n]", &ptr->Name);.
"%s" format specifier of printf requires an arugment of type char * but you have been passing char type to it. The correct statement is printf("Name is: %s\n", ptr->Name);.
-
#include <stdio.h>
#define DEFAULT_NAME_SIZE 200
struct rec {
char Name[DEFAULT_NAME_SIZE];
} emp[100];
int main()
{
int x;
int i;
struct rec *ptr = NULL;
ptr = emp;
printf("Enter Number of Clients: ");
scanf("%d", &x);
getchar();
for (i=0; i< x; i++){
printf("Enter Name: ");
scanf("%[^\n]", ptr->Name);
getchar();
ptr++;
printf("\n");
}
ptr = emp;
for (i = 0; i < x; i++){
printf("Name is: %s\n", ptr->Name);
ptr++;
}
return 0;
}
You can try to enable all warning while you compile your code. Most of the bugs can be pointed by the compiler's warning message.

char *Name;
You never allocated space for the name. Did you mean
char Name[100]
?
This should work, until somebody enters too long of a name. You will get to buffer overflow later and learn about dynamic memory allocation.

When scanning or printing strings, we don't use & and * for referencing and dereferencing pointers, but we must also alloc and free space for them. Fixed your code:
#include <stdio.h>
#include <stdlib.h>
struct rec {
char *Name;
}emp[100];
int main() {
int x;
int i;
struct rec *ptr = NULL;
ptr = emp;
printf("Enter Number of Clients: ");
scanf("%d", &x);
getchar();
for(i=0; i!=x; i++)
{
printf("Enter Name: ");
/* alloc space for string pointer */
ptr->Name = (char*) malloc(sizeof(char)*10);
scanf("%s[^\n]",ptr->Name);
getchar();
ptr++;
printf("\n");
}
i = 0;
/* reset array pointer position */
ptr=emp;
while(i!=x)
{
printf("Name is: %s\n", (ptr->Name));
/* free space for string pointer */
free(ptr->Name);
i++;
ptr++;
}
}
PS: Remember resetting a pointer to the initial position whenever using pointers to arrays.

Related

How to fix format error for char* and char**

i'm writing a kind of phonebook program and i'm using typedef struct to store the name and number of the people. The user will input name and number as a string format, but when i try to scan it, the compiler gives me an error saying "format specifies type char * but the argument has type char **. Any solution on this? i really don't understand what it means. Error is on first loop on both scans any help would be appreciated. Thanks!
#include <stdlib.h>
#include <string.h>
typedef struct
{
char *name;
char *number;
}
person;
int main(void)
{
int n;
scanf("%i", &n);
person people[n];
for(int i = 0; i < n; i++)
{
scanf("%s", &people[i].name); // these 2 lines are buggy
scanf("%s", &people[i].number);
}
char *findName;
scanf("%s", &findName);
for(int i = 0; i < n; i++)
{
if(strcmp(people[i].name, findName) == 0)
{
printf("%s\n", people[i].number);
}
else
{
return 1;
}
}
return 0;
}
The statement
scanf("%s", &people[i].name);
is wrong for two reasons:
First of all the %s format expects a char * argument. By using the address-of operator you get a value of type char **. Mismatching format specifier and argument type leads to undefined behavior.
If you remove the address-of operator you will pass an uninitialized pointer, it's not pointing anywhere valid. This means scanf will write the string to some seemingly random location in memory. Again this leads to undefined behavior.
A simple way to solve the second issue, you could change the structure to contain arrays of characters instead, as in:
typedef struct
{
char name[64];
char number[64];
}
person;
Then use a limit in the format so the scanf function will not attempt to read a string longer than the arrays:
scanf("%63s", people[i].name); // The array decays to a pointer to its first element
Note that the length in the format is 63, so the string null-terminator will fit in the array.
Never use the "%s" format with scanf(). You cannot use it safely.
The problem is, that the user controls how many characters will get written into the memory buffer, but the program needs to supply the memory buffer without knowing how many characters the user is actually going to input. The result is invariable buffer overrun vulnerabilities of your program. Don't do this.
Instead, use allocating input functions. For scanf(), you need to add the "m" modifier:
scanf("%ms", &people[i].name);
This changes the expected argument type from char* to char**, it will malloc() a sufficiently sized buffer for you, and store the address at the given location. I.e, this call does precisely what you want it to do. Just don't forget to free() the resulting string once you are done with it.
The "m" modifier works with the "%ms", "%m[" and "%mc" conversion specifiers, i.e. all the conversions that can output a string of unknown length.
(The other allocating input functions that you should keep in mind are getline() and getdelim().)
findname is already a char *.
You ask for reference of this value, it represent char **
scanf("%s", &findName);
Try this :
scanf("%s", findName);
Here is an example with dynamically allocated memory and scanf with %ms:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct
{
char *name;
char *number;
}
person;
int main(void)
{
int n = 0;
char *findName ;
scanf("%i", &n);
if (n == 0) return 1;
person* people = (person*)malloc(n * sizeof(person));
if (people == NULL) return 1;
for(int i = 0; i < n; i++)
{
person p = people[i];
printf("Enter Name and number:\n");
printf("Number: ");
scanf("%ms", &(p.number));
printf("Name: ");
scanf("%ms", &(p.name));
people[i] = p;
}
printf("Enter name to search: ");
scanf("%ms", &findName);
printf("Searching for: %s\n", findName);
for(int i = 0; i < n; i++)
{
person p = people[i];
if(strcmp(p.name, findName) == 0)
{
printf("Number for %s is %s\n", p.name, p.number);
}
}
free(findName);
for(int i = 0; i < n; i++)
{
//notice how we have to free the strings for each name and number,
// and not just the people array
free(people[i].name);
free(people[i].number);
}
free(people);
return 0;
}

How to fix my code to read a string in a function that returns a pointer to a struct

I'm writing a code that uses a function to return a pointer to a struct, which is allocated dynamically. However, my code isn't reading strings. When I run it, it simply jumps the "Type name" part, I type the age, and it prints the age and nothing for the name. Strangely, the code works when I use scanf to read the string, but it didn't with gets or fgets. Could anyone please help me? Thanks in advance.
#include <stdio.h>
#include <stdlib.h>
struct details
{
char name[100];
int age;
};
struct details * details_pointer(int n)
{
struct details *pointer = (struct details *) malloc (n*sizeof(struct details));
for (int i=0; i<n; i++)
{
printf("Student %d:\n", i);
printf("name:\n");
scanf("%s", pointer[i].name);
//gets(pointer[i].name); not working
//fgets(pointer[i].name, 100, stdin); not working
printf("age:\n");
scanf("%d", &pointer[i]. age);
}
return pointer;
}
int main()
{
int n;
printf("Type the number of persons:\n");
scanf("%d", &n);
struct details *student = details_pointer(n);
for (int i=0; i<n; i++)
{
printf("\nName: %s", (*(student+i)).name);
printf("Age: %d\n", (*(student+i)).age);
}
free(student);
system("pause");
return 0;
}
This is because scanf leaves a newline in the input stream. fgets gets it as the name when it is called. To prove this, change:
scanf("%d", &n);
to something like:
n = 1;
and you will see no problem.
If you don't want to use scanf, you can call fgets then atoi/strtol.
char *num;
fgets(num, 100, stdin);
n = atoi(num);

C compiler error: undefined reference to function

After I execute the exe I get this error :
undefined reference to `StudentScan'
error: ld returned 1 exit status|
Note: I'm bad and new to coding so don't mind my bad coding please^^
Note2: I'm just messing with random functions.
#include <stdio.h>
#include <stdlib.h>
struct student {
char firstName[20];
char AverageNum[2];
};
void StudentScan(int, struct student[]);
void StudentPrint(int, struct student[]);
int main() {
int i;
int length;
struct student *studentp;
printf ("\nEnter the host of students: ");
scanf ("%d ", &length);
struct student list[length];
studentp=malloc(length*sizeof(struct student));
if (studentp==NULL)
{
printf("Out of memory!");
return 0;
}
for(i = 0; i < length; i++) {
StudentScan(i,studentp);
printf("\nEnter average number: ");
scanf("%s", list[i].AverageNum);
}
free (studentp);
void StudentScan(int i, struct student list[])
{ printf("\nEnter first name : ");
scanf("%s", list[i].firstName);
printf("\nEnter average number: ");
scanf("%s", list[i].AverageNum);
}
return 0;
}
The posted code has defined StudentScan() within main(). But nested function definitions are not allowed in C. This should generate a compiler warning, such as:
warning: ISO C forbids nested functions [-Wpedantic]
void StudentScan(int i, struct student list[])
Pay attention to all compiler warnings and fix them. If no warning is seen when compiling this code, turn up the level of compiler warnings. On gcc, I suggest to always use at least gcc -Wall -Wextra, and I always add -Wpedantic. The -Wpedantic is needed with gcc to see a warning for this. Some compilers, and gcc is one of these, do support nested function definitions as a compiler extension. Still, this feature is nonstandard, and it is best to not rely on it.
The fix is simple: move the definition of StudentScan() out of main():
#include <stdio.h>
#include <stdlib.h>
struct student {
char firstName[20];
char AverageNum[2];
};
void StudentScan(int, struct student[]);
void StudentPrint(int, struct student[]);
int main(void) {
int i;
int length;
struct student *studentp;
printf ("\nEnter the host of students: ");
scanf ("%d ", &length);
struct student list[length];
studentp=malloc(length*sizeof(struct student));
if (studentp==NULL)
{
printf("Out of memory!");
return 0;
}
for(i = 0; i < length; i++) {
StudentScan(i,studentp);
printf("\nEnter average number: ");
scanf("%s", list[i].AverageNum);
}
free (studentp);
return 0;
}
void StudentScan(int i, struct student list[])
{ printf("\nEnter first name : ");
scanf("%s", list[i].firstName);
printf("\nEnter average number: ");
scanf("%s", list[i].AverageNum);
}
Also note that you should always specify maximum widths when reading strings using scanf() family functions with %s or %[] to avoid buffer overflow. For example:
scanf("%19s", list[i].firstName);
Note that 19 is used, even though the firstName field is an array of 20 char values. Remember that one space must be reserved for the \0 terminator. And since you are using %s to read a string into the AverageNum field, you should also have:
scanf("%1s", list[i].AverageNum);
That is, this field can only hold one digit. If the intention is to hold two digits, this field must be changed within the struct to: char AverageNum[3].
And while we are discussing scanf(), note that this function returns the number of successful assignments made during the function call. If no assignments are made, 0 is returned. This return value should always be checked. Consider: if the user mistakenly enters a letter when a digit is expected, nothing is stored in the intended variable. This may lead to undefined behavior. You may try something like this to validate numeric input:
printf ("\nEnter the host of students: ");
while (scanf ("%d ", &length) < 1) {
puts("Please enter a number");
int c;
while ((c = getchar()) != '\n' && c != EOF) {
continue;
}
}
This code asks the user to enter input again if a number is not entered when expected. Note that if the user does enter a non-digit, this character remains in the input stream and must be cleared before attempting to process more user input. The while loop is a typical construction which accomplishes this task.
Edit
Based on comments made by the OP, here is a modified version of the posted code. This version uses a float value instead of a character array for the AverageNum field of the struct. A floating-point type may be more useful than an integer type for storing averages. It is usually best to use double for floating-point values, but in this case it looks like AverageNum has little need for precision (the char array was intended to hold only two digits); float is probably sufficient for this use. If a different type is desired, it is simple enough to modify the code below.
Some input validation is implemented, but note that more could be done. The user is prompted to enter a number when non-numeric input is found where numeric input is expected. The input stream is cleaned with the while loop construction after such an input mistake; it would be good to remove this code to a separate function called clear_input(), for example.
If the user signals end-of-file from the keyboard, scanf() will return EOF; the code below chooses to exit with an error message rather than continue with malformed input in this case. This could also occur with input redirected from a file, and this condition may need to be handled differently if such input is expected.
The loop that populated the list[] array seemed to be operating inefficiently, asking for AverageNum twice in each pass. This has been streamlined.
Note that the call to malloc() can be rewritten as:
studentp = malloc(length * sizeof *studentp);
This is a very idiomatic way of writing such an allocation. Here, instead of using an explicit type as the operand of sizeof, that is, instead of sizeof (struct student), the variable which holds the address of the allocation is used. sizeof only uses the type of the expression *studentp, so this variable is not dereferenced here. Coding this way is less error-prone and easier to maintain when types change during the maintenance life of the code.
Yet, it is unclear why memory is allocated for studentp in the first place. In the posted code, both the firstName and AverageNum fields are filled for members of the dynamically allocated studentp in calls to StudentScan() in a loop; the same loop fills the AverageNum field of the members of list[] (a different array of structs) with different input. There seems to be no need for one of these arrays of student structs; I have commented-out the dynamically allocated array in favor of the statically allocated version.
Here is the modified code:
#include <stdio.h>
#include <stdlib.h>
struct student {
char firstName[20];
float AverageNum;
};
void StudentScan(int, struct student[]);
void StudentPrint(int, struct student[]);
int main(void) {
int i;
int length;
// struct student *studentp;
printf ("\nEnter the host of students: ");
while (scanf ("%d", &length) < 1) {
puts("Please enter a number");
int c;
while ((c = getchar()) != '\n' && c != EOF) {
continue;
}
}
struct student list[length];
/* This is fine */
// studentp = malloc(length * sizeof (struct student));
/* But this is better */
// studentp = malloc(length * sizeof *studentp);
// if (studentp == NULL)
// {
/* Not wrong, but... */
// printf("Out of memory!");
// return 0;
// fprintf(stderr, "Allocation failure\n");
// exit(EXIT_FAILURE);
// }
for(i = 0; i < length; i++) {
StudentScan(i, list);
}
/* Code to display results here */
// free (studentp);
return 0;
}
void StudentScan(int i, struct student list[])
{
putchar('\n');
printf("Enter first name: ");
if (scanf("%19s", list[i].firstName) != 1) {
puts("Input error");
exit(EXIT_FAILURE);
}
printf("Enter average number: ");
while (scanf("%f", &list[i].AverageNum) < 1) {
puts("Please enter a number");
int c;
while ((c = getchar()) != '\n' && c != EOF) {
continue;
}
}
}
You have to remove the scan function from the main. Also there is not a printstudent function you are declaring. You must remove /n from the printf and the scanf functions and place them accordingly. You can then test if your data are being added correctly in your struct with a simple loop.
#include <stdio.h>
#include <stdlib.h>
struct student {
char firstName[20];
char AverageNum[2];
};
int main() {
int i=0;
int length;
struct student *studentp;
printf ("Enter the host of students:");
scanf ("%d", &length);
struct student list[length];
studentp=malloc(length*sizeof(struct student));
if (studentp==NULL)
{
printf("Out of memory!");
return 0;
}
for(i = 0; i < length; i++) {
printf("Enter first name :");
scanf("%s", list[i].firstName);
printf("Enter average number: ");
scanf("%1s", list[i].AverageNum);
}
for(i = 0; i< length; i++){
printf("number of host is: %d , his/her first name: %s , his/her avg number: %s \n", i, list[i].firstName, list[i].AverageNum);
}
free (studentp);
return 0;
}

array changes when i change parameter

So i have this code in c.It all works fine until i get to the point to read word again.It gets the new word but also the (*A)[size-1] takes the price of the new word.How do i prevent this?
void fuction(char ***A,char ***B,int size)
{
char word[20],word2[20];
printf("Type word .\n");
gets(word);
while(strcmp(word,"0")!=0)
{
printf("Type second word.\n");
gets(word2);
printf("%d",size);
**A=realloc(**A,(size+1)*sizeof(char));
**B=realloc(**B,(size+1)*sizeof(char));
(*A)[size-1]=word;
(*B)[size-1]=word2;
size++;
printf("Type another word to add or 0 to exit.\n");//**it all works fine**
gets(word);
}
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void function(char ***A, char ***B, int *size){
char word[32], word2[32];
printf("Type first word.\n");
scanf("%31s", word);
while(strcmp(word,"0")!=0){
printf("Type second word.\n");
scanf("%31s", word2);
*A =realloc(*A, (*size+1)*sizeof(char*));
*B =realloc(*B, (*size+1)*sizeof(char*));
(*A)[*size]=strdup(word);
(*B)[*size]=strdup(word2);
++*size;
printf("Type another word to add or 0 to exit.\n");
scanf("%31s", word);
}
}
int main(void){
int i, size = 0;
char **w1, **w2;
w1 = w2 = NULL;
function(&w1, &w2, &size);
for(i = 0; i < size; ++i){
printf("%s, %s\n", w1[i], w2[i]);
free(w1[i]);free(w2[i]);
}
free(w1);free(w2);
return 0;
}
Turns out the problem was that i didnt allocate memory for the words in the array.I added these lines and it worked.Thank you for your answers.
(*A)[size-1]=(char*) malloc(31);
(*B)[size-1]=(char*) malloc(31);
This
(*A)[size-1]=word;
(*B)[size-1]=word2;
is not what you think it is.
In c, this means you are assigning the address to the first element of the array word to (*A)[size-1] if you want this to work, provided that you have allocated memory for (*A)[size-1] you should do it this way
strcpy((*A)[size-1], word);
strcpy((*B)[size-1], word2);
You should think about why do you need char ***, generally you wont need more than char **, and don't use gets() use fgets() instead.

Runtime Error with Printing Double Pointer Char Array

I am working on creating a system for entering student names and scores into arrays and printing the same information to the screen, unfortunately I keep getting the weird output.
I stepped through my program using a debugger and it showed that everything runs smooth until I get to the function that prints the student's information, there the double pointer char arrays have messed up values.
Here's an image of what I see when I run the program. (http://s28.postimg.org/nv29feawt/Error.png)
Note: Although I am aware that there are better and easier ways of doing this I am required to complete this assignment using dynamically allocated memory and arrays.
int main(void)
{
char **firstNames;
char **lastNames;
float *scores;
int recordsLength;
printf("Please indicate the number of records you want to enter: ");
scanf("%d", &recordsLength);
printf("\n\n");
firstNames = (char **)malloc(recordsLength * sizeof(char *));
lastNames = (char **)malloc(recordsLength * sizeof(char *));
scores = (float *)malloc(recordsLength * sizeof(float));
int i = 0;
while(i < recordsLength)
{
createNewEntry(i, firstNames, lastNames, scores);
i++;
}
printEntry(0, firstNames, lastNames, scores);
free(firstNames);
free(lastNames);
free(scores);
return 0;
}
void clearScreen()
{
#ifdef _WIN32
system("cls");
#elif _unix_
system("clear");
#endif
}
void printEntry(int entryID, char *firstNames[], char *lastNames[], float scores[])
{
clearScreen();
printf("|-------------------------------------------------------------------------|\n");
printf("| Student Entry |\n");
printf("|-------------------------------------------------------------------------|\n|\n");
printf("| First Name: %s Last Name: %s Score: %.1f\n|\n|\n|\n", firstNames[entryID], lastNames[entryID], scores[entryID]);
printf("|-------------------------------------------------------------------------|\n");
printf("| |\n");
printf("|-------------------------------------------------------------------------|\n\n");
}
void createNewEntry(int index, char *firstNames[], char *lastNames[], float scores[])
{
printf("Please input the records of the new student.\n\n\n");
char first[20];
char last[20];
float score = 100.0f;
printf("Please enter the student's first name: ");
scanf("%s", &first);
printf("\n\n");
printf("Please enter the student's last name: ");
scanf("%s", &last);
printf("\n\n");
printf("Please enter the student's score: ");
scanf("%f", &score);
printf("\n\n");
firstNames[index] = (char *)malloc((strlen(first)) * sizeof(char));
firstNames[index] = first;
lastNames[index] = (char *)malloc((strlen(last)) * sizeof(char));
lastNames[index] = last;
printf("first name: %s", firstNames[index]);
printf("last name: %s", lastNames[index]);
scores[index] = score;
}
firstNames[index] = (char *)malloc((strlen(first)) * sizeof(char));
firstNames[index] = first; /* You are missing your allocated memory block and assigning local */
Above lines are incorrect. You can not assign c-strings with assignation = operator. You should use strcpy for that.
You are assigning local array to firstnames, which has no life after the function ends. This invokes an undefined behavior. (You are seeing the strange characters, but it can be even worse).
Should be Re-written as (Similar for last name also)
firstNames[index] = malloc((strlen(first) + 1) * sizeof(char)); /* +1 for \0 */
if(firstNames[index] == NULL) {
/* Malloc failed, error handling */
...
}
/* else */
strcpy(firstNames[index], first); /* Use strcpy to copy contents */
Live example here
Before freeing firstNames and lastNames, you should free all the member of firstNames and lastNames in a loop.
I agree with the answer of Mohit Jain, adding to that you can even use sprintf.

Resources