How to put strings from a file into an array in c - c

So I have this code:
char inte[10];
while(j<noinput) {
fscanf(circuit,"%s",inte);
vararray[count]=inte;
count++;
j++;
}
However when I print the contents of the array like this:
for (h=0;h<noinput+2;h++){
printf("%dth variable: %s\n",h,vararray[h]);
}
The elements past the first two (which are reserved for special elements) are all equal to the LAST string that I had taken in from fscanf earlier. I have no idea how one of the strings from fscanf could be equal to multiple slots in the array when I am only setting
vararray[count]=inte;
Shouldn't this mean that each element of the array will be different since I am incrementing count every time? I am so confused. I also tried doing:
fscanf(circuit,"%s",vararray[count]);
But this also did not work and gave me null elements for certain indexes.

you are doing something too wrong. By "vararray[count]=inte;" you are doing pointer assignment so all of your vararray is getting filled by same string. I am guessing you are new to C so I will answer due to that. Correct way would look something like below
Fixed size solution:
char vararray[ROWCOUNT][BUFFERSIZE];
for(count=0; j<noinput; ++count, ++j) {
fscanf(circuit,"%s",(char*)vararray[count]);
}
With dynamic memory management
char * vararray[ROWCOUNT];
for(count=0; j<noinput; ++count, ++j) {
vararray[count] = (char*)malloc(BUFSIZE);
fscanf(circuit,"%s", vararray[count]);
}
I want to warn you in the way of becoming an expert on C nowadays is somewhat madness , i mean unless you have another choice. Examples below I put and the thing you wrote are completely unsafe and unsecure...

You're not copying the string. Here's what's happening:
char *vararray[462]; // declare an array of string pointers
char inte[10]; // declare a char array (to function as a string)
for (int i = 0; i < 462; i += 1) {
// do something
vararray[i] = inte;
}
This is causing all of the items of vararray to point to the memory also referred to as inte... but you're overwriting that each time! Instead, do something like this:
#include <string.h> // write me at the top, outside main()!
char vararray[462][10]; // declare an array of strings (max length 9)
char inte[10]; // declare a char array (to function as a string)
for (int i = 0; i < 462; i += 1) {
fscanf(circuit,"%10s",inte); // use buffer size to make xscanf safer
strncpy(vararray[i], inte, 9); // copy inte, making sure not to buffer overflow!
vararray[i][9] = '\0'; // if inte is too big, a null byte won't be added to the end of the string; make sure that it's there
}
This copies the string! Your problem should go away when you do this.

Related

Insert a string inside of another string (without an intermediate string)

I came across this question and it asks if it's possible to write the function
void insert(char* M, char* T, int i)
that inserts the string T inside M starting from the index i, without using an intermediate string... I tried to use realloc but I think there's a problem when the original string M is a lot smaller than the result, my theory is that realloc changes the address of the string to be able to represent the new string.
For example: M="Wg" T="ron" and i=1; the result should be M="Wrong".
I'm using the following code:
void insert(char* M,char* T,int i)
{
int l;
l=strlen(M);
M=realloc(M,l+strlen(T)+1);
for(int j = l-1; j >= i; j--)
{
M[j+strlen(T)]=M[j];
}
for(int j = 0;j < strlen(T); j++)
{
M[i+j]=T[j];
}
M[l+strlen(T)]='\0'; //from what i've tested the string M is correct.
}
and using this declaration:
char *s=malloc(3);
char *c=malloc(18);
strcpy(s,"as");
strcpy(c,"bcdefghijklmnopqr");
insert(s,c,1); //this example does not work on my machine.
I hope this clarifies the question.
So is there a way to do it?
Example of a possible implementation using memmove. Explanations are in the comments
#include <stdio.h>
#include <string.h>
void insertString(char* M, const char* T, size_t index)
{
// ASSUMES there's enough space in M for this operation
// get the original lengths of each string
size_t Mlen = strlen(M);
size_t Tlen = strlen(T);
if (index < Mlen)
{
// M+index+Tlen is the destination position where the remaining characters in M will start
// M+index is the index where T will be inserted
// Mlen-index is the remaining number of characters in M that need to move
memmove(M+index+Tlen, M+index, Mlen-index);
// copy the T string to the space we just created
memcpy(M+index, T, Tlen);
// NUL terminate the new string
M[Mlen + Tlen] = '\0';
}
else
{
// simply strcat if the index falls outside the range of M
strcat(M, T);
}
}
If you're not allowed to use memmove or memcpy, it's simple enough to roll your own.
Demo
[This isn't really an answer; it's a clarification that's too complicated for a comment.]
If you can assume that the caller looks like
char string[6] = "Wg";
insert(string, "ron", 1);
(or with the string array having any size greater than 5), then you can write insert() easily.
If you can assume that the caller looks like
char *string = malloc(3);
strcpy(string, "Wg");
insert(string, "ron", 1);
then you can almost write insert() using realloc to make the string larger, except you have no way to return the possibly-new (that is, possibly moved) value of string.
If the caller might look like
char *string = "Wg";
insert(string, "ron", 1);
or even
char *string = "Wg\0\0\0";
insert(string, "ron", 1);
than you definitely cannot write insert(), because you cannot assume that the pointed-to string is writable (and on many platforms it will not be).
So, in general, the answer is: "No". You cannot write a general-purpose version of insert() that will work under all circumstances.
Note, too, that if you were to assume that the string were in malloc'ed memory and that you could use realloc (as in my second example), that code would not work for strings that were not malloc'ed (that is, it would not work for callers like my first example), and it would have no portable way of knowing, based on the pointer passed to it, whether it would be abe to safely use realloc or not.

C - how to use strcpy for a 2 dimensional array?

I'm trying to build a 2 dimensional array by using str.cpy, but the program fails. The code receives 4 arrays add copies their content to their matching arrays.
int InsertStudent(char *firstName, char* lastName, char* dynCourses, char *dynGrades,
char firstNames[50][20],
char familyNames[50][20], char courses[50][5][20],
char grades[50][5])
{
int set,
int cset = 0;
for (set = 0; set <= (50); set++)
{
if (firstNames[set][cset] == '\0')
{
strcpy(firstNames[set][cset], firstName);
strcpy(familyNames[set], lastName);
for (cset = 0; cset <= 5; cset++)
{
strcpy(courses[set], dynCourses);
strcpy(grades[set], dynGrades);
}
}
}
return 0;
}
Well clearly the error is using strcpy wrongly.
The correct way would be
strcpy(firstNames[set], firstName);
Also in the loop it should be
for (cset = 0; cset < MAX_COURSES; cset++)
{
strcpy(courses[cset], dynCourses);
strcpy(grades[cset], dynGrades);
}
Note that the idiomatic C loop is for (int i = 0; i < MAX; i++), using < and not <=.
The signature of the strcpy function is
char *strcpy(char * restrict s1, const char * restrict s2);
Earlier you passed in place of s1 a char instead of char*. You must have got some warning (if enabled). If not then turn all compiler flags -Wall -Werror.
if (firstNames[set][cset] == '\0')
But if you are initially checking an uninitilized value with \0. This will higly unlikely will turn out to be false. There is no gurantee that the char array which doesn't contain strings will be initialized with 0 automatically. So make sure you have initialized the char arrays in the callee function like this
char arr[20][50]={0};
The loop is from 0 to MAX_STUDENTS. You are invoking an undefined behavior looping on array index out of bound if MAX_STUDENTS is greater than or equal to 50. Same goes for MAX_COURSES. More clearly the looping would be for (set = 0; set < (50); set++).
Again there will be a lot better way to deal with it if you put the initialization and copy part seperate. Otherwise this will be uneasy to maintain.
Seeing your use courses it is obvious that you want to declare it like this
char courses[5][20];
same goes for the grades array. Here you were trying to copy a string into into a 2d array. Compiler would complain about type incompatibility.
Also in the function you didn't return anything meaningful. The correct way would be to return the index value on which new name or information is added.
Here you are copying content of dynGrades and dynCourses to the array. So they will all contain the same values. Is this what you want? Because then what's the use of keeping 5 seperate char arrays - one could serve the purpose pretty well.

How to create an array of strings in C dynamically without knowing the size of strings and characters?

I have tried everything and my code looks perfectly fine to me (it obviously isn't if it's not working).
I am trying to read from some text a list of words separated by a comma, and each word will be an element of an array of strings. I don't know how many elements there will be or how long it will be.
The for loop is grand, as I count how many characters there is before. The main problem is allocation memory, sometimes I get "Segmentation Fault: 11" when I run it (as it compiles grand), sometimes when I read the items it get something like:
P?? adios (null) heyya
When it should give me something like:
hola adios bye heyya
I think I am accessing memory I am not supposed to. Anyway, here the code:
// We allocate memory for one string
variables = (char**)calloc(1, sizeof(char*));
variables[0] = (char*)calloc(100, sizeof(char));
if (variables == NULL) {
return NULL;
}
// Now we start looking for the variables
for (int i = comma_pos+1; i < *(second_pos + pos); i++) {
deleteSpaces(string, &i);
// If the character is not a comma, we copy the character
if (*(string + i) != ',') {
*(variables[stringnum] + j) = *(string + i);
j++;
} else {
// If the character is a comma, we have to allocate more memory for a new string
*(variables[stringnum] + j) = '\0';
stringnum++;
j = 0;
char **temp = variables;
// We allocate more memory for a second array
variables = realloc(variables, sizeof(char*) * stringnum);
variables[stringnum] = (char*)calloc(100, sizeof(char));
// If we cannot allocate more memory then get out
if (variables == NULL) {
return temp;
}
} // end else
} // end for
*(variables[stringnum] + j) = '\0';
It's not immediately clear to me what is wrong with your code, but it's not at all how I would approach the problem.
I would start by determining how many substrings there are by counting delimiters in the source string and adding one. This does require a pre-scan of the string, but it's likely to be much cheaper than any alternative that requires performing multiple memory allocations.
As for space for the strings themselves, if you do not need to keep the comma-delimited form of the list, then you may be able to re-use that space. Use the strtok() function to tokenize it, and store the resulting pointers.
If you must preserve the original comma-delimited string, then I suggest making a copy of the whole thing, and then tokenizing as I suggested before (and you will know how long it is already from counting delimiters). You do not need more space overall for the individual strings than the original comma-delimited one occupies.
If you prefer to avoid strtok() then it's not hard to implement the same thing manually.
you have to alloc in both directions and maybe you are already.
you need to allocate the depth, an array of pointers, then for each pointer in that array need to allocate the width for that row.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main ( void )
{
unsigned int ra;
unsigned int rb;
char **x;
x=malloc(100*sizeof(char *));
printf("%p\n",x);
for(ra=0;ra<100;ra++)
{
x[ra]=malloc(ra*sizeof(char));
}
for(ra=0;ra<100;ra++)
{
printf("%p\n",x[ra]);
}
for(ra=0;ra<100;ra++)
{
for(rb=0;rb<ra;rb++) x[ra][rb]=rb;
}
for(ra=0;ra<100;ra++)
{
for(rb=0;rb<ra;rb++)
{
printf("%u ",x[ra][rb]);
}
printf("\n");
}
return(0);
}

To know the size of an array in c

I am learning C language. I want to know the size of an array inside a function. This function receive a pointer pointing to the first element to the array. I don't want to send the size value like a function parameter.
My code is:
#include <stdio.h>
void ShowArray(short* a);
int main (int argc, char* argv[])
{
short vec[] = { 0, 1, 2, 3, 4 };
short* p = &vec[0];
ShowArray(p);
return 0;
}
void ShowArray(short* a)
{
short i = 0;
while( *(a + i) != NULL )
{
printf("%hd ", *(a + i) );
++i;
}
printf("\n");
}
My code doesn't show any number. How can I fix it?
Thanks.
Arrays in C are simply ways to allocate contiguous memory locations and are not "objects" as you might find in other languages. Therefore, when you allocate an array (e.g. int numbers[5];) you're specifying how much physical memory you want to reserve for your array.
However, that doesn't tell you how many valid entries you have in the (conceptual) list for which the physical array is being used at any specific point in time.
Therefore, you're required to keep the actual length of the "list" as a separate variable (e.g. size_t numbers_cnt = 0;).
I don't want to send the size value like a function parameter.
Since you don't want to do this, one alternative is to use a struct and build an array type yourself. For example:
struct int_array_t {
int *data;
size_t length;
};
This way, you could use it in a way similar to:
struct int_array_t array;
array.data = // malloc for array data here...
array.length = 0;
// ...
some_function_call(array); // send the "object", not multiple arguments
Now you don't have to write: some_other_function(data, length);, which is what you originally wanted to avoid.
To work with it, you could simply do something like this:
void display_array(struct int_array_t array)
{
size_t i;
printf("[");
for(i = 0; i < array.length; ++i)
printf("%d, ", array.data[i]);
printf("]\n");
}
I think this is a better and more reliable alternative than another suggestion of trying to fill the array with sentinel values (e.g. -1), which would be more difficult to work with in non-trivial programs (e.g. understand, maintain, debug, etc) and, AFAIK, is not considered good practice either.
For example, your current array is an array of shorts, which would mean that the proposed sentinel value of -1 can no longer be considered a valid entry within this array. You'd also need to zero out everything in the memory block, just in case some of those sentinels were already present in the allocated memory.
Lastly, as you use it, it still wouldn't tell you what the actual length of your array is. If you don't track this in a separate variable, then you'll have to calculate the length at runtime by looping over all the data in your array until you come across a sentinel value (e.g. -1), which is going to impact performance.
In other words, to find the length, you'd have to do something like:
size_t len = 0;
while(arr[len++] != -1); // this is O(N)
printf("Length is %u\n", len);
The strlen function already suffers from this performance problem, having a time-complexity of O(N), because it has to process the entire string until it finds the NULL char to return the length.
Relying on sentinel values is also unsafe and has produced countless bugs and security vulnerabilities in C and C++ programs, to the point where even Microsoft recommends banning their use as a way to help prevent more security holes.
I think there's no need to create this kind of problem. Compare the above, with simply writing:
// this is O(1), does not rely on sentinels, and makes a program safer
printf("Length is %u\n", array.length);
As you add/remove elements into array.data you can simply write array.length++ or array.length-- to keep track of the actual amount of valid entries. All of these are constant-time operations.
You should also keep the maximum size of the array (what you used in malloc) around so that you can make sure that array.length never goes beyond said limit. Otherwise you'd get a segfault.
One way, is to use a terminator that is unique from any value in the array. For example, you want to pass an array of ints. You know that you never use the value -1. So you can use that as your terminator:
#define TERM (-1)
void print(int *arr)
{
for (; *arr != TERM; ++arr)
printf("%d\n", *arr);
}
But this approach is usually not used, because the sentinel could be a valid number. So normally, you will have to pass the length.
You can't use sizeof inside of the function, because as soon as you pass the array, it decays into a pointer to the first element. Thus, sizeof arr will be the size of a pointer on your machine.
#include <stdio.h>
void ShowArray(short* a);
int main (int argc, char* argv[])
{
short vec[] = { 0, 1, 2, 3, 4 };
short* p = &vec[0];
ShowArray(p);
return 0;
}
void ShowArray(short* a)
{
short i = 0;
short j;
j = sizeof(*a) / sizeof(short);
while( i < j )
{
printf("%hd ", *(a + i) );
++i;
}
printf("\n");
}
Not sure if this will work tho give it a try (I don't have a pc at the moment)

Array out of bounds, index -1

I basically want to store a array of student names, based on a given number. For example, if the user wants to insert 5 names, then the array size will be 5. If the user wants to insert 10 names, then the array size will be 10.
I have a method like this to set a name to a specific element in an array.
void setNames(char *names){
strcpy(name[i], names);
}
Thing is, how do I do array bound checks? I heard that you can only add when the index is -1.
Arrays don't maintain their own size, you have to do that for them. This is part of the reason why vectors are so much easier to deal with, and why everyone will say "wtf, raw arrays? use a vector". An array is just a contiguous chunk of memory, thats it. a vector contains an array, and lets you use it like an array to some extent, but it handles a lot of the housekeeping details for you.
Anyway, if you really want to use a raw array, then you'll need to pass around size information along with it. C strings are a null-terminated array -- just a plain old array, but the last element is \0. This way you can read from it without knowing it's size ahead of time, just don't read past the null character at the end (dragons be there).
EDIT (as the OP indicated he actually wants C):
C answer
What you can do is either create a char array:
char [N][name_length]
where N - number "user wants" (I assume the user will somehow input it into your program), name_length - maximum length the name can have (a C-string, i.e. null-terminated string).
or create an array of your own structs (each holding a separate name and maybe some other information).
C++ answer
A typical way to do this in C++ is by using std::vector<std::string> (assuming you only want to store names, as std::string).
You then add new elements using using push_back() function. And, as vector is implemented as a dynamic array in C++, you won't have to do bound checking.
C code needs to keep track of the array size in another variable.
typedef struct {
char **name;
size_t n;
} Names_T;
void Names_Set(Names_T *names, size_t index, const char *name) {
// See if it is a special value and then append to the array
if (index == (size_t) -1) {
index = names->n;
}
if (index >= names->n) {
size_t newsize = index + 1;
// OOM error handling omitted
names->name = realloc(names->name, newsize * sizeof *names->name);
while (names->n < newsize) {
names->name[names->n++] = NULL;
}
}
char *oldname = names->name[index];
names->name[index] = strdup(name);
free(oldname);
}
void Names_Delete(Names_T *names) {
while (names->n > 0) {
names->n--;
free(&names->name[names->n]);
names->name[names->n] = NULL;
}
free(names->name);
names->name = NULL;
}
int main(void) {
Names_T names = { NULL, 0 };
Names_Set(&names, 3, "Sam"); // set array element 3
Names_Set(&names, (size_t) -1, "Thers"); // Append to array
Names_Delete(&names);
return 0;
}
When programming in C/C++ (unless using C++11 or newer), you will manipulate arrays as pointers. That means you won't know the size of an array unless you save it. What char str[10] really means is str's address + 10 * sizeof(char). You are directly dealing with memory here.
If you want a high level approach for that, take a look at C++11. std::array and std::vector are there for you. From the documentation, look how std::array is defined:
template <
class T,
std::size_t N
> struct array;
It means it stores its own size and has useful functions as well, such as size(), at(), back() etc.

Resources