I have created a C program where I'm supposed to read a text file and assign it to a structure through int and string pointers.
Here's a code snippet of my program:
i = 0;
while(!feof(phoneBook)) {
fscanf(phoneBook, "%d|%s\n", &num, fname);
info[i].phone_num = num;
printf("%d\n", info[i].phone_num);
info[i].first_name = fname;
printf("%s\n", info[i].first_name);
i++;
ctr++;
printf("\nfirst:%s", info[0].first_name);
printf("\nsecond:%s", info[1].first_name);
printf("\nthird:%s\n\n", info[2].first_name);
}
On the first iteration, it assigns the first line to the 0 index of info.
For the second iteration, it assigns the second line to index 1 AND replaces index 0.
The text file only contains the following lines (for testing purposes):
first
second
third
Here's the output:
//first iteration
first:first
second: <null>
third: <null>
//second
first:second
second: second
third: <null>
//third
first:third
second: third
third: third
By the way, I declared my structure as:
typedef struct{
int id;
char *first_name;
char *last_name;
int phone_num;
} phone_det;
where phoneBook was declared under the datatype phone_det.
Any form of help would be greatly appreciated! I just started using C and I can still get a little confused with pointers. :(
Although we, can't see your structure, you assign the pointer to the same name buffer each time, and don't copy the name buffer itself to the specific array, so you end up with many different pointers to the same name buffer.
The problem is the assignment info[i].first_name = fname;. This does not make a copy of the string - it simply sets info[i].first_name to point to the same memory that fname points to. So after each iteration, they all point to the same memory that fname points to. Thus, when you fscanf a new value into the buffer, all of the structs see the new contents.
Your assigning info[i].first_name to point to fname; Instead of declaring fname as: char* fname; (as I'm assuming you did), do something like this: char[MAX_SIZE] fname; and then use strcpy to copy over the value. So do: strcpy(info[i].first_name, fname);
This is a guess because I can't see all your code, but I bet you just have char * for these items, that is you are assigning the pointers to a string.
fname is actually a buffer. (maybe a char fname[20]) so each item is pointing to fname which changes with each read.
To fix this problem make the structure contain an array. Then use strcpy or strncpy to copy it from fname.
You should copy the name, rather than point to it. You are setting all your pointer to the location that you read the last name into. Use strcpy or some such.
Or, to make life even simpler, make sure that the first_name element was assigned sufficient space, then read directly into it with
fscanf(phoneBook, "%d|%s\n", &(info[i].phone_num), info[i].first_name);
Each iteration reads into fname, and then assign's fname's address to info[i].first_name. fname's address doesn't change between each iteration, so you're assigning the same address to all of the first_name pointers!
You'll want to allocate an unique array for each iteration so that the strings are stored in different locations, rather than each one overwriting the last.
while(!feof(phoneBook)) {
char *fname = malloc(SUITABLY_LARGE_SIZE);
if (fname == NULL) {
perror("malloc");
exit(1);
}
fscanf(phoneBook, "%d|%s\n", &num, fname);
info[i].first_name = fname;
...
}
Related
C function to remove the first string from an XOR linked list of names:
int remove_string(Node **head, char *deleted_string) {
Node *temp = *head;
*deleted_string = *(*head)->name;
*head = calculate_xor_value(NULL, temp->xor_value);
if (*head != NULL) {
(*head)->xor_value = calculate_xor_value(NULL, calculate_xor_value(temp, (*head)->xor_value));
}
free(temp);
}
In the question, one of the input parameters has to be a char pointer called deleted_string, which is the string that is being removed from the list. The code to remove the string works fine (line 4 onwards), but I am struggling to save the string to the char* deleted_string (line 3) *deleted_string = *(*head)->name;
Everytime I run the code
// printf("%s", deleted_string ); only the first character is being printed; I think I understand that this is because pointers only point to the first character of a string, but is there a way to make the pointer point to the whole string? Perhaps by somehow converting (*head)->name to a string or an array?
Any help would be appreciated, sorry if this is a silly question. I have spent hours trying to find another page about this but I didn't so I thought I'd ask.
Assuming (*head)->name is of type char*, you are dereferencing both the char *deleted_string and char *name, hence operating on something of type char.
The line
*deleted_string = *(*head)->name;
is equivalent of doing something like
char a;
char b = 0;
a = b;
If you want to copy the contents of (*head)->name into the deleted_string, you can use strcpy or strncpy like,
strncpy( deleted_string, (*head)->name, SIZE );
Where the SIZE is whatever maximum size the deleted_string can hold. strcpy is the same, just without the size argument.
As comments suggested, both should be used with care, as strcpy can attempt to copy more characters than the destination can hold, causing write violations, and strncpy will truncate if the source is bigger than the destination, the resulting string will not necessarily be null-terminated. In such case, functions that assume the string is null-terminated will misbehave, such as printf( "%s" ... ), causing read violations. For more information, you can check this post.
I am first concatenating a series of elements in an auxiliary char array to then assign the concatenated array to the pointer. The problem comes when assigning this char array to the pointer, where it produces a segmentation fault.
My approach was the following one:
char aux_name [12];
char * name = (char *) malloc(sizeof(char)*13);
int i;
for(i = 0; i < 5; i++){
sprintf(aux_name, "id_%i", i);
*name = (void *) (intptr_t) aux_name; //Conflict line
//Do something with variable name (it is required a pointer)
}
You don't assign a pointer value to an already malloc()-ed pointer, you'll be facing memory-leak there. You have to use strcpy() to achieve what you want.
OTOH, if you don't allocate memory dynamically, then you can assign the pointer like
name = aux_name;
That said,
I am first concatenating a series of elements in an auxiliary char array
Well, you're not. you're simply overwriting the array every time in every iteration. What you need to do is
Collect the return value of sprintf() every time.
next iteration, advance the pointer to buffer by that many locations to concatinate the new input after the previous one.
Note / Suggestion:
do not cast the return value of malloc() and family in C.
sizeof(char) is guranteed to be 1 in c standard. You don't need to use that, simply drop that part.
You can't do that, and you don't really need to, this would work
size_t nonConstanSizeInBytes = 14;
char *name = malloc(nonConstanSizeInBytes);
snprintf(name, 13, "id_%i", i);
i want to make a strncpy function so i try to make it but i can't.
i made a struct. struct have int age ; and char name[20]. so i want to name[20] copy strings which from scanf. but it fail... how can i make a
strlcpy function?
(*list).name++ = name++;
is error... if this is work, i can make a strncpy.
void makeUserList (Unit* list, const char *name, int age ){
while (*name) {
NSLog(#"%c",*name);
(*list).name++ = name++;
// (list->name)++ = name++;
NSLog(#"%c",*list[roomNum].name);
}
i'm from korea. please understand my english grammar...
Have a nice daY~
First of all, the code (*list).name++ = name++; will copy only one character. It should be repeated for the whole length of name. Second: This code will modify the list's name field as well, such that it will point to the end of the copied string, which is obviously not what you want. If you want this to work, you should copy the destination pointer and work with this copy. Look here for example.
I need to read in a file. The first line of the file is the number of lines in the file and it returns an array of strings, with the last element being a NULL indicating the end of the array.
char **read_file(char *fname)
{
char **dict;
printf("Reading %s\n", fname);
FILE *d = fopen(fname, "r");
if (! d) return NULL;
// Get the number of lines in the file
//the first line in the file is the number of lines, so I have to get 0th element
char *size;
fscanf(d, "%s[^\n]", size);
int filesize = atoi(size);
// Allocate memory for the array of character pointers
dict = NULL; // Change this
// Read in the rest of the file, allocting memory for each string
// as we go.
// NULL termination. Last entry in the array should be NULL.
printf("Done\n");
return dict;
}
I put some comments because I know that's what I'm to do, but I can't seem to figure out how to put it in actual code.
To solve this problem you need to do one of two things.
Read the file as characters then convert to integers.
Read the file directly as integers.
For the first, you would use freed into a char array and then use atoi to convert to integer.
For the second, you would use fscanf and use the %d specify to read directly into an int variable;
fscanf does not allocate memory for you. Passing it a random pointer as you have will only cause trouble. (I recommend avoid fscanf).
The question code has a flaw:
char *size;
fscanf(d, "%s[^\n]", size);
Although the above may compile, it will not function as expected at runtime. The problem is that fscanf() needs the memory address of where to write the parsed value. While size is a pointer that can store a memory address, it is uninitialized, and points to no specific memory in the process' memory map.
The following may be a better replacement:
fscanf(d, " %d%*c", &filesize);
See my version of the spoiler code here
I am under the impression that on each run, in my Strings array, I am storing at pos a new str since I am declaring it everytime, instead, on the 2nd run if addstr become hello, and on the first run It was hi, the first run hi also becomes hello. I just want a different char array on each run in Strings so later on each position I have a different strings. The requirements is that I can not use malloc, realloc, calloc. I really thought that on the 2nd iteration of the first for loop I am creating on a char str independent of the previous one. Please help me.
int pos = 0;
for(i=0; i<4; i++)
{
if(file [i]=='a')
{
char str[5];
int b=0;
for(b; b<3; bi++)
{
str[b]=file[b];
}
Strings[pos]=str;
pos++;
}
}
When you do this:
Strings[pos]=str;
It merely sets that array element to the buffer pointed to by 'str'. It does not copy the string. The 'str' buffer never changes, so your entire array ends up pointing to the same buffer.
Rather, at that line you need to copy the string. If you can't use malloc, then your Strings array needs to have buffers at each array element (aka 2 dimensional array). Maybe declare it something like:
char Strings[5][5];
Then instead of using your strcpy to copy to 'str', copy the string to 'Strings[pos]';