My question refers to the while(!feof(arch)) that repeats the last registry two times. Thanks if you take some of your time to answer. I'm in first year learning basics.
The information is on an archive, so the first input shouldn't be 's' because it isn't the first time to input. Then the program list the infomation but the last registry repeats two times.
#include <stdio.h>
typedef struct{
int legajo;
char nombre[30];
int ingreso;
int pparcial;
int sparcial;
} reg_alumno;
reg_alumno funcionleer(void);
typedef FILE * archivo; //Se define el tipo de dato "archivo".
archivo arch; //Se declara una variable de archivo.
int main(void){
reg_alumno alumno,alu;
int ca,i,j=0;
char respuesta;
printf("Desea ingresar datos por primera vez?");
scanf("%c",&respuesta);
printf("Ingrese cantidad alumnos");
scanf("%d",&ca); //Pide cantidad alumnos
if(respuesta=='s'){
arch = fopen("alumnos.dat","w"); //Crear archivo para escribir, crea si no existe)
for(i=0;i<ca;i++){
alumno = funcionleer(); //Lee alumno
fseek(arch,sizeof(reg_alumno)*i,SEEK_SET); //Busca la última posición del archivo
fwrite(&alumno,sizeof(reg_alumno),1,arch); //Escribe en la última posición
}
}
else{
arch = fopen("alumnos.dat","r+");
while(!feof(arch)){
fseek(arch,sizeof(reg_alumno)*j,SEEK_SET); //Pasa de registro en registro(alumno en alumno).
fread(&alu,sizeof(reg_alumno),1,arch); //Trae a la memoria principal un alumno
printf("Legajo N %d: %s\n",alu.legajo,alu.nombre);
j++;
}
}
fclose(arch); //Cierra el archivo
}
reg_alumno funcionleer(void){ //Función leer
reg_alumno alumno;
printf("Ingrese el numero de legajo:\n");
scanf("%d",&alumno.legajo);
printf("Ingrese el nombre:\n");
scanf("%s",alumno.nombre);
return(alumno);
}
Good to check result of IO operations #WhozCraig.
The code's problem is that its prints even if fread() fails.
// No check of return value.
fread(&alu,sizeof(reg_alumno),1,arch);
printf("Legajo N %d: %s\n",alu.legajo,alu.nombre);
Code uses feof() incorrectly. Many SO posts on that.
Since OP implies code is required to use feof() by teacher: following are 2 good ways to use feof()
for (;;) {
if (fseek(arch,sizeof(reg_alumno)*j,SEEK_SET)) break;
if (fread(&alu,sizeof(reg_alumno),1,arch) == 0) break;
printf("Legajo N %d: %s\n",alu.legajo,alu.nombre);
j++;
}
// If loop quit because of EOF
if (feof(arch)) printf("Success");
else if (!ferror(arch)) printf("IO Error");
Or
for (;;) {
if (fseek(arch,sizeof(reg_alumno)*j,SEEK_SET)) break;
fread(&alu,sizeof(reg_alumno),1,arch);
if (!feof(arch)) break;
if (!ferror(arch)) break;
printf("Legajo N %d: %s\n",alu.legajo,alu.nombre);
j++;
}
Related
good morning, I am making a calculator with a "Stack" of 10 positions in the "C" lenguage. What I have to do is, for example, I write the number "50", I press ENTER and that "50" must go to the first position "01". Then I write another number, for example "20" + ENTER and 20 should go to position "01", "50" goes up to "02" and so on, always after pressing ENTER. I am using the Gotoxy for this.
I can manage to print the first number in position "01" but after that I don't know how to proceed.
I'm new to programming so excuse me if I don't realize obvious things, I'm trying to learn so if you can give me a hand I would appreciate it. Here I leave the code in case you want to try it and get an idea of what I'm trying to do, thanks
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
void gotoxy(int x, int y);
void PilaPush();
void ImprimirPila();
int main() {
printf(" ____________________________________________________\n");
printf("|10:_________________________________________________|\r\n");
printf("|09:_________________________________________________|\r\n");
printf("|08:_________________________________________________|\r\n");
printf("|07:_________________________________________________|\r\n");
printf("|06:_________________________________________________|\r\n");
printf("|05:_________________________________________________|\r\n");
printf("|04:_________________________________________________|\r\n");
printf("|03:_________________________________________________|\r\n");
printf("|02:_________________________________________________|\r\n");
printf("|01:_________________________________________________|\r\n");
printf("| |\r\n");
printf("| |\r\n");
printf("|____________________________________________________|\r\n");
printf("|_____1_____|_____2_____|_____3_____|__+__|__DROP[P]_|\r\n");
printf("|_____4_____|_____5_____|_____6_____|__-__|__SWAP[S]_|\r\n");
printf("|_____7_____|_____8_____|_____9_____|__*__|__DEL[D]__|\r\n");
printf("|_____,_____|_____0_____|____EXE____|__/__|__NUM[N]__|\r\n");
printf("|_____'_____|_ARRIBA[W]_|__ABAJO[Z]_|_____|_SWAP1[Q]_|\r\n");
gotoxy(3, 12);
PilaPush();
ImprimirPila();
getch();
return 0;
}
void gotoxy(int x, int y) {
HANDLE Ventana;
Ventana = GetStdHandle(STD_OUTPUT_HANDLE);
COORD Coordenadas;
Coordenadas.X = x;
Coordenadas.Y = y;
SetConsoleCursorPosition(Ventana, Coordenadas);
}
typedef struct Nodo {
int elemento;
struct Nodo *siguiente;
} Nodo;
// funciones para utilizar un manejador global
Nodo *primero = NULL;
// Insertar un nuevo nodo a la pila
void PilaPush() {
Nodo *nuevo;
// crear el nuevo Nodo.
nuevo = (Nodo *)malloc(sizeof(Nodo)); // Asignar de forma dinamica un espacio de memoria al Nodo
printf(" ");
scanf("%d", &nuevo->elemento);
// Agregar el nodo al principio de la Pila
nuevo->siguiente = primero; // El nuevo dato ahora es primero, que apunta a (NULL)
primero = nuevo; // Primero (NULL) ahora es el nuevo dato
}
// sacar un elemento de una pila
void ImprimirPila() {
Nodo *actual = (Nodo *)malloc(sizeof(Nodo));
actual = primero;
if (primero != NULL) {
while (actual != NULL) {
gotoxy(9, 10);
printf("%d", actual->elemento);
actual = actual->siguiente;
gotoxy(3, 12);
printf(" ");
gotoxy(3, 12);
}
} else {
printf("No hay ningun dato ");
}
}
sorry for any mistakes, my native language is not english.
I need help with my code:
// Esse programa lê dados de um arquivo TXT, contendo nome, altura e peso
// entao ele retorna esses mesmos dados, alem de informar o IMC da pessoa que esta nos dados
// informando tambem se é obesa ou magra etc.
// Raphael Azambuja Silva Macedo 2020
#include <stdio.h>
#include <stdlib.h>
// Estruturas
typedef struct // Struct das pessoas
{
char nome[100];
int peso;
float altura;
} pessoa;
// Prototipos
float imc(int peso, float altura);
void showIMC(float imcalculado);
void showP(char nome[100], int peso, float altura);
void mIMC(char nome1[100], char nome2[100], int peso1, int peso2, float altura1, float altura2);
pessoa getP(char fns[100]);
// Variaveis externas
const int MAXFN = 50;
int
main()
{
int i=0; // Contador
int n,m; // Valor da struct das pessoas comparadas
char fn[MAXFN]; // Nome do arquivo
float valorimc; // valor do IMC
FILE *file = NULL; // Ponteiro que abre o arquivo
printf("\nDigite o nome do arquivo: ");
scanf("%s", fn);
file = fopen(fn, "r");
if (file == NULL) // Checagem para ver se o arquivo abriu corretamente
{
fprintf(stderr, "ARQUIVO NAO PODE SER ABERTO");
return 0;
}
pessoa z[4]; // Variavel Z da struct pessoa
for (i = 0; i<4 ; i++)
{
z[i] = getP(fn);
valorimc = imc(z[i].peso,z[i].altura); // Chamando a função que calcula o resultado
showP(z[i].nome,z[i].peso,z[i].altura); // Chamando a função que mostra os dados
showIMC(valorimc); // Chamando a função que calcula e mostra o IMC
}
printf("\n=================\n");
printf ("\n\nDigite a enumeracao das pessoas que quer comparar o IMC, sendo a primeira ''0''\n");
scanf(" %d",&n);
scanf(" %d",&m);
mIMC(z[n].nome,z[m].nome,z[n].peso,z[m].peso,z[n].altura, z[i].altura);
fclose(file);
return 0;
}
float // Função que calcula o IMC
imc(int peso, float altura)
{
float resultado;
resultado = peso / (altura*altura);
return resultado;
}
void
showIMC(float imcalculado) // Função que mostra os dados do IMC
{
printf("O IMC dessa pessoa eh: %f" ,imcalculado);
if (imcalculado <= 18.5)
{
printf("\nMagreza");
}
else if (imcalculado > 18.5 && imcalculado <= 24.9)
{
printf("\nPeso normal");
}
else if (imcalculado > 24.9 && imcalculado <= 30)
{
printf("\nSobrepeso");
}
else
{
printf("\nObesidade");
}
}
void
showP(char nome[100], int peso, float altura) // Função que mostra os dados da pessoa
{
printf("\n=================\n");
printf("Nome da pessoa: %s\nPeso da pessoa: %d\nAltura da Pessoa: %f\n",nome,peso,altura);
}
void // Função que compara ambos IMC
mIMC(char nome1[100], char nome2[100], int peso1, int peso2, float altura1, float altura2)
{
int IMC1,IMC2; // IMC de cada Pessoa
IMC1= peso1 / (altura1*altura1);
IMC2= peso2 / (altura2*altura2);
if (IMC1>IMC2)
{
printf("\n=====================\n");
printf("A pessoa %s tem o menor IMC." ,nome2);
}
else if (IMC2>IMC1)
{
printf("\n=====================\n");
printf("A pessoa %s tem o menor IMC." ,nome1);
}
else
{
printf("\n=====================\n");
printf("As duas pessoas tem o mesmo IMC.");
}
}
pessoa getP(char fns[100])
{
pessoa t;
FILE *file = fopen(fns, "r");
fscanf (file, " %[^0123456789] %d %f" ,t.nome,&t.peso,&t.altura);
return t;
}
What I need to do is:
Every time I call the ''getP'' function I need to read a diferent line of info from the txt file, however, every time the function is called it starts reading from the beginning, so I always get the first line.
The txt file is:
beltano das couves 90 1.7
fulano de tal 80 1.7
sicrano de tel 75 1.7
deltrano de tol 70 1.7
The Exercise is about filling Products names with their Stock capacity in file named fichierProduit and filling the movement (Import and Export) of this products in file named fichierMouvment. After filling these 2 files I create another file fichierdeResultat so I can write in it the new Stock Capacity. After doing some math the function related to this is ResultatdeMouvement, when displaying the Result it only displays the first product.
I tried to copy the name into the record "Resultat" (R) and then write it into the fichierdeResultat while displaying them in the function AfficheDeProduitApresMouvement it seems displaying only the first product name in file fichierProduit.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
struct Produit{
char NomP[10] ;
int StockP;
};
struct Mouvement{
char MouveP[10];
int MouveAp;
int MouveV;
};
struct Resultat{
char NomPr[10];
int StockR;
};
//INSERTING NEW PRODUCTS LIST
void SaisirProduits(FILE* ficheierProduit){
struct Produit P;
ficheierProduit = fopen("C:/Users/Ayoub/Desktop/EX5/EX5/FProduit.dat","wb");
char rep;
do {
fseek(ficheierProduit, 0, SEEK_END);
printf("Saisir Nom de Produit: ");
scanf("%9s",&P.NomP);
printf("Saisir Capacite de Stock de Produit: ");
scanf("%i",&P.StockP);
fwrite (&P, sizeof(struct Produit), 1,ficheierProduit);
if(fwrite!=0){
printf("\n\Produit Ajoute avec succees !\n\n");
}
printf("Voulez Vouz Saisir un autre Produit (O,N): ");
scanf(" %c",&rep);
}while(toupper(rep)!='N');
fclose(ficheierProduit);
}
//INSERTING NEW MOVEMENT LIST
void SaisirMouvement(FILE* fichierMouvment){
struct Mouvement M;
fichierMouvment = fopen("C:/Users/Ayoub/Desktop/EX5/EX5/FMouvment.dat","wb");
char rep;
do {
fseek(fichierMouvment, 0, SEEK_END);
printf("Saisir Nom de Produit a Ajouter un mouvement: ");
scanf("%9s",&M.MouveP);
printf("Saisir Capacite d'approvisionnement: ");
scanf("%i",&M.MouveAp);
printf("Saisir Nombre Vendu de ce Produit: ");
scanf("%i",&M.MouveV);
fwrite (&M, sizeof(struct Mouvement), 1,fichierMouvment);
if(fwrite!=0){
printf("\n\Mouvement Ajoute avec succees !\n\n");
}
printf("Voulez Vouz Saisir un autre Mouvement (O,N): ");
scanf(" %c",&rep);
}while(toupper(rep)!='N');
fclose(fichierMouvment);
}
//Function to verify if the Products Exist or not
int VerifierProduitExistouNon(char NomdeProduit[10],FILE* ficheierProduit){
struct Produit P; ficheierProduit=fopen("C:/Users/Ayoub/Desktop/EX5/EX5/FProduit.dat","r+");
int found=0;
while(!feof(ficheierProduit)){
fread(&P,sizeof(P),1,ficheierProduit);
if(strcmp(P.NomP,NomdeProduit)==0){
found=1;
return found;
}else if(feof(ficheierProduit) && found==0)
return found;
}
fclose(ficheierProduit);
}
//Add New Products to the File
void AjouterNouveauProduit(FILE* fichierProduit){
struct Produit P;
fichierProduit=fopen("C:/Users/Ayoub/Desktop/EX5/EX5/FProduit.dat","ab+");
printf("Saisir Nom de Nouveau Produit: ");
scanf("%9s",&P.NomP);
if(VerifierProduitExistouNon(P.NomP,fichierProduit)!=0)
printf("\n\nProduit deja Exist Merci de Verifier !\n\n");
else{
printf("\nSaisir Capcite de Stock de Produit: ");
scanf("%i",&P.StockP);
fwrite (&P, sizeof(struct Produit), 1,fichierProduit);
printf("\nSaisir de nouveau Produit avec Success ! \n");
}
fclose(fichierProduit);
}
//INSERTING NEW MOUVEMENT
void AjouterNouveauMouvement(FILE* fichierMouvment,FILE* fichierProduit){
struct Mouvement M;
fichierMouvment = fopen("C:/Users/Ayoub/Desktop/EX5/EX5/FMouvment.dat","ab+");
printf("Saisir Nom de Produit a Verifier S'il exist: ");
scanf("%9s",&M.MouveP);
if(VerifierProduitExistouNon(M.MouveP,fichierProduit)!=0){
printf("\n\nProduit Exist Ajout de Nouveau Mouvement.....\n\n");
printf("\nSaisir Capcite d'approvisionnement de Ce Produit: ");
scanf("%i",&M.MouveAp);
printf("\nSaisir Capcite de Vente de Ce Produit: ");
scanf("%i",&M.MouveV);
fwrite (&M, sizeof(struct Mouvement), 1,fichierMouvment);
if(fwrite!=0){
printf("\nSaisir de nouveau Produit avec Success ! \n");
}
}else{
printf("\n\nCe Produit N existe pas dans le Stock Merci de Verifier ! \n\n");
}
fclose(fichierMouvment);
}
//TRYING TO FILE THE RESULT FILE
void ResultatdeMouvement(FILE* ficheierProduit,FILE* fichierMouvment,FILE* fichierResultat){
struct Produit P;
struct Mouvement M;
struct Resultat R; ficheierProduit=fopen("C:/Users/Ayoub/Desktop/EX5/EX5/FProduit.dat","r+");
fichierMouvment=fopen("C:/Users/Ayoub/Desktop/EX5/EX5/FMouvment.dat","r+");
fichierResultat=fopen("C:/Users/Ayoub/Desktop/EX5/EX5/FResultat.dat","wb");
while(!feof(ficheierProduit)){
fread(&P,sizeof(P),1,ficheierProduit);
while(!feof(fichierMouvment)){
fread(&M,sizeof(M),1,fichierMouvment);
if(strcmp(P.NomP,M.MouveP)==0){
strcpy(R.NomPr,P.NomP);
R.StockR=P.StockP+(M.MouveAp-M.MouveV);
}
}
fwrite(&R,sizeof(R),1,fichierResultat);
}
fclose(ficheierProduit);
fclose(fichierMouvment);
fclose(fichierResultat);
}
void AfficheDeMouvement(FILE* fichierdeMouvement){
struct Mouvement M;
fichierdeMouvement=fopen("C:/Users/Ayoub/Desktop/EX5/EX5/FMouvment.dat","r+");
while(fread(&M,sizeof(M),1,fichierdeMouvement)){
printf("\n\nNom de Produit: %s | approvisionnement= %i | Vente= %i\n\n ",M.MouveP,M.MouveAp,M.MouveV);
}
fclose(fichierdeMouvement);
}
void AfficheDeProduitavantMouvement(FILE* fichierProduit){
struct Produit P;
fichierProduit=fopen("C:/Users/Ayoub/Desktop/EX5/EX5/FProduit.dat","r+");
while(fread(&P,sizeof(P),1,fichierProduit)){
printf("\n\nNom de Produit: %s | Stock Valable = %i \n\n",P.NomP,P.StockP);
}
fclose(fichierProduit);
}
void AfficheDeProduitApresMouvement(FILE* fichierResultat){
struct Resultat R;
fichierResultat=fopen("C:/Users/Ayoub/Desktop/EX5/EX5/FResultat.dat","r+");
while(fread(&R,sizeof(R),1,fichierResultat)){
printf("\n\nNom de Produit: %s | Stock Valable Apres Mouvement: %i \n",R.NomPr,R.StockR);
}
fclose(fichierResultat);
}
//Main
int main()
{ FILE* Produit;//file of the products
FILE* MouvementdeProduit;//file of the mouvment
FILE* ResultatdeMouvedeProduit;//file of the result
AfficheDeProduitavantMouvement(Produit);
AfficheDeMouvement(MouvementdeProduit); ResultatdeMouvement(Produit,MouvementdeProduit,ResultatdeMouvedeProduit);
AfficheDeProduitApresMouvement(ResultatdeMouvedeProduit);
}
There are many problems with your code, some of which I addressed in the comments. I will/did not identify all problems. I will just point you to the problem you are asking about.
The problem is that you skip a lot of records in the input file, so before processing the next product you must rewind the input file:
while(fread(&P,sizeof(P),1,ficheierProduit))
{
// You now have a product.
// Now collect its stock.
R.StockR= 0;
*R.NomPr= '\0';
while(fread(&M,sizeof(M),1,fichierMouvment))
{
if(strcmp(P.NomP,M.MouveP)==0){
strcpy(R.NomPr,P.NomP);
R.StockR=P.StockP+(M.MouveAp-M.MouveV);
}
}
if (*R.NomPr!='\0') fwrite(&R,sizeof(R),1,fichierResultat);
// You have now possibly skipped lots of products.
// So you must rewind the file.
fseek(fichierMouvment,0, SEEK_SET);
}
I am trying to assign different error messages to the error variable in each case by passing a pointer to the string between functions but for any reason is not working well.
Here is the code:
//This function takes a pointer to a char.
int lee(Fecha *f, char *error){
int checking;
printf("Introduzca una fecha compuesta por día, mes, y año\n");
checking = scanf("%i %i %i", &f->day, &f->month, &f->year);
printf("%d\n", checking);
switch (checking){
case 0:
//The message is assigned to the space where error points to.
*error = "Formato de fecha incorrecto. El día debe ser un entero.";
break;
case 1:
*error = "Formato de fecha incorrecto. El mes debe ser un entero.";
break;
case 2:
*error = "Formato de fecha incorrecto. El año debe ser un entero.";
break;
}
return (checking == 3);
}
int main(){
Fecha f;
//error is declared like a pointer
char * error;
int ret;
//The pointer is passed to the function as argument.
ret = lee(&f, error);
printf("%s", error);
return 0;
}
And the output:
user#console:~/$ ./Sesion1
Introduzca una fecha compuesta por día, mes, y año (o 0 0 0 para terminar el programa)
23 dfgadkfhgsñdgh 5
1
Segmentation fault
Since you want to make an output to the string, you need to pass pointer to your char*, so you need to pass error as char**.
So the function will be
int lee(Fecha *f, char **error){
int checking;
printf("Introduzca una fecha compuesta por día, mes, y año\n");
checking = scanf("%i %i %i", &f->day, &f->month, &f->year);
printf("%d\n", checking);
switch (checking){
case 0:
//The message is assigned to the space where error points to.
*error = "Formato de fecha incorrecto. El día debe ser un entero.";
break;
case 1:
*error = "Formato de fecha incorrecto. El mes debe ser un entero.";
break;
case 2:
*error = "Formato de fecha incorrecto. El año debe ser un entero.";
break;
}
return (checking == 3);
}
int main(){
Fecha f;
//error is declared like a pointer
char * error;
int ret;
//The pointer is passed to the function as argument.
ret = lee(&f, &error);
printf("%s", error);
return 0;
}
Also, you should consider not leaving pointers without value after declaration like you did with char* error in main().
The problem is, when you have a pointer that is not initialized and then you forget to give it a value or something like this, it can point anywhere within your application memory (or beyond it). Virtual memory protects you from reading and writing to others applications memory (generally speaking), but you can have a case where the pointer happens to point to some data inside your application. And if you then use this pointer to write or read, you will have unpredictable result, ranging from just displaying erroneous data to corrupting data or crashing application, which you obviously do not want.
You need to pass a pointer to your function output parameters. Since your output parameter is char*, the pointer to it is char**.
To fix, change the corresponding lines to:
int lee(Fecha *f, char **error);
// ...
ret = lee(&f, &error);
I'm new in C, and I'm trying some exercises that I found.
In one of the exercises I'm trying to use a pointer to a string (a char array), but it doesn't work. It compiles, but when is executed, it throws "stack overflow" (well, I think is an "stack overflow" because I have it in spanish).
These are the problematic lines:
//This is the variable declaration, before this, there is the "main function" declaration
char entrada[100];
char *ult=entrada;
char cantidadstr[10];
int i,j,k = 0;
int res;
scanf ("%s",entrada);
printf ("\n%s",entrada);
//Here crashes
printf ("Hola %s",ult);
while (*ult != "\0"){
//And here there's more code
Thank you in advance!!
EDIT
(I can't answer me :))
Then, I'll post a bit more of code.
When I execute, after inserting data, it throws "Violación de segmento", and google says that means Stack Overflow
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main(void){
char entrada[1001*11*101];
/*Asi tenemos el tamano maximo:
1001 por las 1000 posibles lineas, mas la primera
11 por el tamano maximo del numero (1 + 9 ceros), mas el espacio o salto de linea siguiente
101 por el numero de numeros por linea, mas el primero
*/
char *ult=entrada;
char cantidadstr[10];
int i,j,k = 0;
int res;
memset (entrada,'\0',1001*11*101);
scanf ("%s",entrada);
printf ("\n%s",entrada);
//poniendo ese print ahi arriba, ese me lo muestra, por tanto, el fallo esta en el puntero de debajo de esta linea
printf ("Hola %s",ult);
while (*ult != "\0"){
if(*ult == "\n"){
if(i != 0){
printf("\n");
}
i++;
j = 0;
}
else if(i != 0){
if(*ult == " "){
j++;
k=0;
res = atoi(cantidadstr);
printf("%d ",res*2);
//Este es el otro cambio que hablaba
cantidadstr[10] = '\0';
}
else if(j != 0){
cantidadstr[k] = *ult;
}
}
k++;
*ult++;
}
return 0;
}
This is the exact and full code, with comments in spanish for another forum. The size of "entrada" is big enough for any data send in the exercise. The "memset" is just added. The second comment shows where it crashes
Thank you for your quick answer!!
The code before the while loop is fine as it compiles and runs correctly(as far as i can think)
But the while loop has an error i'm not sure how it compiled in your case.
because you have written
while (*ult != "\0"){
which gives compiler error as
*ult is of type char
"\0" is of type const char*
you have to convert "\0" to '\0'
The following line:
cantidadstr[10] = '\0';
will write past the end of cantidadstr, which is definitely bad and most likely causing your stack overflow. If you want to null terminate cantidadstr, use cantidadstr[9]= '\0';. Arrays in C are zero based, not one based, so the first element of an array of size N starts at [0] and the last referenceable element is [N-1].